I am having an issue with persisting a collection define URL for CRUD operations after I delete a model. I have a few models, one for each contact. Currently I run a this.model.destroy when I want to delete a contact, though as soon as I destroy the model, I am getting an undefined status for the collection defined URL. Is there a way to re-establish the collection-defined URL for all other models after a destroy?
I have tried to define a rootURL, which seems to work after a deleted contact, however, if I am not deleting a contact, then I get multiple requests to send the same contact with different ID's
Here is the Delete functionality:
deleteContact: function() {
if (!this.model) {
return;
}
this.model.destroy({
success: function(model, response) {
App.Emitter.trigger('snackbar', 'Contact Deleted!', 3000);
App.Emitter.trigger('contacts:close');
App.Master.changeView('contacts');
Backbone.Collection.fetch()
// App.Contacts2.remove(this.model);
},
error: function(model, response) {
console.info('contact save error');
App.Emitter.trigger('snackbar', 'ERROR Deleting!', 3000);
}
});
},
I am getting an error:
"
app.min.js:1552 Uncaught Error: A "url" property or function must be specified"
It turns out that even though I was removing the Model, the view was sticking around in the background. The URL issue I was receiving was being thrown since it is a required field (but being thrown from a 'ghost' view that stacked up in the background). Thanks for the help.
Related
I have been working to create an API which programatically creates/updates work item in Azure Devops. I have been able to create a work item and populate almost all fields. I have problem with setting the state.
When I am creating a POST request to Azure Devops rest api with any state name like "Active", "Closed", "Rejected", it throws a 400 Bad Request error.
I don't know if I am missing anything or if there something wrong with the way I am trying to set the value.
{
"op" : "add",
"path": "/fields/System.State",
"value"="Active",
}
I have found the solution to this problem and hence I am answering it here.
I was getting a 400 Bad Request error whenever I tried Creating an Item and Setting the state in the same call. I debugged the code and caught the exception. I found out that, there are some validation rules for some of the fields. State is one of them.
The rule for System.State field is, whenever a Work Item is created it takes its configured default value. ( In my case it was "Proposed", in your case it could be "New"). If you try altering the value at the time of work item creation, it throws a 400 Bad Request.
What should I do if I have to Create a Work Item with a specific State?
As of now, the solution that I have found out is to make two calls. One for Work Item Creation and another for Changing the state of the work item to desired state.
CreateWorkItem()
{
var result = await _client.Post(url, jsonData);
var result2 = await _client.Put(result.id, jsonData); // or maybe just the state
return Ok(result2);
}
Check the example here: Update a field
You have to use "value":"Active" in the request body.
[
{
"op" : "add",
"path": "/fields/System.State",
"value": "Active"
}
]
I have a table where users are allowed to "tick" or "cross" out a row. Ticking a row changes the status value to "Approved" and crossing it changes it to "Disapproved". I'm currently using the Edit scaffold to perform it. How do I do this without having the user being redirected to the view. I just want the user to click it and the page refreshes, with the status value being updated.
I'm not sure what code to post here either since I don't know how to write it. If any part of my program is required, please let me know. I'll include it here. Thank you :>
Add css classes to the 2 buttons "approve-btn" and "reject-btn".
Create javascript function to approve and reject and bind them to
the 2 classes
Create 2 backend functions
Make ajax calls from the JS functions to your backend functions passing the id of the row item
In the "success:" of the ajax call manage the change of the status to show "approved" or "rejected"
To make ajax call you can use the following example (although there are tons of example on google). Since you're modifying data you should use POST call and since it is a POST call, you should add a RequestVerificationToken to prevent CSRF attacks.
function Approve(id){
securityToken = $('[name=__RequestVerificationToken]').val();
$.ajax({
url: '/YourControllerName/Approve/' + itemId,
type: 'POST',
data: {
"__RequestVerificationToken": securityToken
},
success: function (data) {
if (data == 'success')
//use jQuery to show the approved message;
else
alert("something went wrong");
},
error: function (request, err) {
alert("something went wrong");
}
});
}
The Token should be created in the View adding this line:
#Html.AntiForgeryToken()
I am using ti.storekit to do in app billing. Everything seems to work, but when I run the following code:
Storekit.requestProducts(["FooPro"], function (evt)
{
Ti.API.info('evt:' + JSON.stringify(evt, undefined, 2));
//hideLoading();
if (!evt.success)
{
alert('ERROR: We failed to talk to Apple!');
}
else if (evt.invalid)
{
alert('ERROR: We requested an invalid product!');
}
else
{
item = evt.products;
Ti.API.info('gotProducts:' + JSON.stringify(item, undefined, 2));
success(item[0]);
}
});
I get a successful response, but with no products:
evt:{
"type": "callback",
"products": [
{}
],
"source": {},
"success": true
}
So there is no products, and just silently fails. In iTunes connect, in the product, i have an in app product with the product id of FooPro (although it is pending review). I am not sure what else I am doing wrong. everything seems to work, i just get back an empty products array and I cant figure out why.
This is also causing the error so that when I call
// product = {} since the above returned it as empty
Storekit.purchase(product);
it errors and tells me this as well:
Passing individual args to `purchase` is DEPRECATED. Call `purchase` passing in a dictionary of arguments.
addTransactionObserver` should be called before `purchase`
EDIT: the products, when using Ti.API.info() to output the contents show as empty. Yet after signing into itunes with the test account on the device, the products still do show up as empty, but when I do more debugging, the product object seems to actually be:
{'My product description'}
So when I call
Storekit.purchase(product)
It seems like it's really calling
Storekit.purchase({'My product description'})
So it appears to be failing here because the purchase call never triggers the transactionState event listener.
Environment:
- iPhone: 5, 4s
Thanks for any help.
Whow... I've been playing around with it further, and there is something weired going on...
Even when you get [{}] for products, products[0].title brings back the actual product title.
It's as though it's there, but hiding from the trace statement.
All you then needed to do is send {product:e.products[0]} to purchase, and voila :
Storekit.requestProducts(productIDs, function(e) {
Ti.API.info("GOT PRODUCTS : "+JSON.stringify(e));
// 'GOT PRODUCTS : {"type":"callback","products":[{}],"source":{},"success":true}'
Ti.API.info('PROD TITLE : '+e.products[0].title);
// 'PROD TITLE : My IAP product'
Storekit.purchase({product:e.products[0]});
// You need to implement 'transactionState' and addTransactionObserver to carry on from here - see the example code in the module package for that
});
And make sure you set Storekit.autoFinishTransactions = false; - or you won't get the final purchase event after the user has bought your product.
I'm struggling to debug this error because, although it's consistently reported, the app's behavior is as intended. Would appreciate pointers as to what it means and how I could go about debugging its source.
Apologies for being vague but, since I'm getting the desired result, I'm unsure what other information to provide.
UPDATE
I've created a repro of this issue and attempted to focus the code on the problem. The error is thrown consistently even though the database is updated correctly. There's a single saveChanges in the code and it uses the save functionality from the dataservice.js in the Breeze Todo sample. SaveOptions.allowConcurrentSaves is false.
Entirely at a loss to explain it and have looked through my EF code to see whether I'm making an obvious mistake but can't see it. The bundle sent to the WebAPI SaveChanges method looks correct (correctly populated with IDs etc.) too.
https://github.com/DazWilkin/BreezeJS.ScoreIssue
UPDATE 6th February
The issue remains unresolved by Wade's helpful answer. Unfortunately, unless I can understand what it is I'm doing wrong or learn that this is a bug, I'm going to have to abandon the use of Breeze in this project and revert to crappy, plain old AJAX calls.
It would appear that the issue revolves around the server returning a zeroed GUID when saving changes. The method returns no errors. I would be thrilled to learn that this is a bug in my entity model but I'm doubtful.
Here's the failure:
breeze.debug.js: 11954
var ix = this._indexMap[tempValue];
if (ix === undefined) {
throw new Error("Internal Error in key fixup - unable to locate entity");
}
When the code reaches this point, the value of this._indexMap is correct and is:
{"bcb6e670-00fc-469d-8531-5767f40bf3c1":0}
BUT the value of tempValue (as returned from the Web API call by the server) is wrong:
00000000-0000-0000-0000-000000000000
The realValue is correct and is:
1093b975-7686-4621-8336-77c38ed36de0
Backing up the stack. Here are the results from the AJAX call, breeze.debug.js: 12574. See that the tempValue is zeroed on return from the server/WebAPI call. The realValue is correct. This is what the database contains. The row is added to the table without problem.
"KeyMappings": [
{
"$id": "4",
"$type": "Breeze.WebApi.KeyMapping, Breeze.WebApi",
"EntityTypeName": "...Score",
"TempValue": "51877f5b-811f-4260-bd5b-cf9965159597",
"RealValue": "92b73b8a-8b33-45cd-9822-ca7c0c5d5d9a"
},
{
"$id": "5",
"$type": "Breeze.WebApi.KeyMapping, Breeze.WebApi",
"EntityTypeName": "...PropertyValue",
"TempValue": "00000000-0000-0000-0000-000000000000",
"RealValue": "1093b975-7686-4621-8336-77c38ed36de0"
}
],
Verified against what's received serverside in saveBundle. NB the IDs of both entities received at the server have valid GUID IDs.
"entities": [
{
"ID": "51877f5b-811f-4260-bd5b-cf9965159597",
...
"entityAspect": {
"entityTypeName": "Score:...",
"entityState": "Added",
"originalValuesMap": {},
"autoGeneratedKey": {
"propertyName": "ID",
"autoGeneratedKeyType": "Identity"
}
}
},
{
"ID": "bcb6e670-00fc-469d-8531-5767f40bf3c1",
...
"entityAspect": {
"entityTypeName": "PropertyValue:...",
"entityState": "Added",
"originalValuesMap": {},
"autoGeneratedKey": {
"propertyName": "ID",
"autoGeneratedKeyType": "Identity"
}
}
}
],
Unsurprisingly, the values sent to the server by the AJAX call that are created in breeze.debug.js: 10494 saveBundleStringified are correct and the same as those received by the server (won't reproduce but I assure you they are).
And, from my code, when the saveChanges is called,
manager.getChanges().length == 2
manager.getChanges()[0].ID() == "51877f5b-811f-4260-bd5b-cf9965159597" (Score)
manager.getChanges()[1].ID() == "bcb6e670-00fc-469d-8531-5767f40bf3c1" (PropertyValue)
and, as expected, these match the (temp) values of the entities' IDs during saveChanges, received by the server...
What am I doing wrong?? If I had hair, I'd be tearing it out!
I've solved it.
My inconsistently applied (!) convention is to make the setters internal/private on code first types. I say inconsistently because, after feeling that I'd exhausted all possibilities, I discovered that the PropertyValue type, i.e. the one originating the error, had an internal set.
Having removed this and rebuilt the solution, the problem is solved!
So:
public Guid ID { get; internal set; }
Should be:
public Guid ID { get; set; }
Update Jan 27:
Based on your comments to Sergey's answer, you may have been trying to do something with the changed entities before the save operation completed.
Those entities remain in their changed state ... often with temporary primary and foreign keys ... until the server reports a successful save.
You probably shouldn't touch them until the save succeeds. As Sergey observes, you should locate your post-save processing in the save success callback.
return manager.saveChanges()
.then(saveSucceeded)
.fail(saveFailed);
You should not wrap the saveChanges call in a jQuery Deferred. That is a waste of time and complexity. The EntityManager.saveChanges method returns a promise that your caller can consume. The view models can add their own success and failure callbacks
dataservice.saveChanges()
.then(hooray)
.fail(sadTrombone);
Concurrent saves
I noticed in your code that you are guarding against illegal concurrent saves using the time-delay approach you found in the Todo sample.
That approach is really only suitable for the demo. It won't work at all for you if your view models need to perform some tasks when the save succeeds. It won't work because the dataservice can't return a promise to the view models with the time-delay approach.
If you need non-blocking saves, check out the "Save Queuing" plugin described in the "Concurrent Saves" topic under the "Cool Breezes" section.
Creating entities succinctly
While looking at your code, I couldn't help noticing that your entity factory methods in scoreissue.1.0.ts were a bit verbose. What you have written as:
export function Business(manager, o: IBusiness) {
var business = manager.metadataStore.getEntityType("Business").createEntity();
business.ID(breeze.core.getUuid());
business.Name(o.name);
manager.addEntity(business);
return business;
}
could be as simple as:
export function Business(manager, o: IBusiness) {
return manager.createEntity("Business", {
ID: breeze.core.getUuid(),
Name: o.name,
});
}
The EntityManager.createEntity shortcut is new since you wrote this code so don't feel bad about having missed it.
Original answer:
[Wrong direction. Preserved to make sense of DazWilkin comment that the problem is on the client.]
Where is this being generated? On the server? If so, you can subclass EFContextProvider and override SaveChangesCore. Call the base.SaveChangesCore and put a try/catch around it. Inspect the saveMap argument. The EFContextProvider is open source; I'd start digging here.
This error can occur with multiple simultaneous save requests pending at the same time both involving key generation. Does this error only occur during a save? If so try setting your SaveOptions.allowConcurrentSaves to false. If this causes a different error, (a concurrent save error) to occur then your problem definitely has to do with concurrent saves.
Hope this helps.
I have the same problem, and I've solved it with help of jQuery deferred object. My dataservice save method now looks as follows:
saveChanges = function () {
var def = $.Deferred();
if (manager.hasChanges()) {
manager.saveChanges()
.then(function () { def.resolve() })
.fail(function (error) {
handleSaveError(error);
def.reject();
});
} else {
logger.info("Nothing to save");
def.resolve();
};
return def.promise();
};
And I call it from my view models also using jQuery deferred object:
$.when(dataservice.saveChanges())
.done(function () {
...some actions
})
I've got a Backbone.js/Rails app and I'm trying to create a new object through Backbone model.save().
The server is returning a 302 moved, but checking the rails controller, the create object exists, and I can navigate to the index, so the routes are properly in place.
I've tried replacing the backbone.js with a regular jquery .ajax function, and both return the 302, as I originally thought the error was in backbone, but I think this is showing that the error is actually in rails.
The request payload/parameters is pretty simple
{"user_id":130,"message_text":"does this go 302","authenticity_token":"GxN8nPf5YwS2j2HhWZxWiKej3Y72Vb5IQZ98u5Nl2gs="}
The backbone save method is
var user_message = new Myapp.Models.UserMessage({
user_id: user.id,
message_text: $('input[name="message"]',this.el).val()
});
user_message.save({
success: function(response) {
new Message({message: response.message});
},
error: function() {
new Error({ message: "adding message" });
}
});
A "302" response has nothing to do with backbone, as you've noted. It looks like you have authorization / authentication code that is causing this.