Backbone.Model.destroy not triggering success function on success - backbone.js

So, within one of my views, I've got this function:
delete_model: function() {
var answer = confirm("Are you sure you want to delete this element?");
if (answer) {
this.model.destroy({
success: function() {
console.log("delete was a success");
}
});
}
});
When I ping that, the Ajax call goes out, the backend properly deletes the model and returns a 200 header with "OK" as the body...but the success event never fires. Am I missing something? What should I have the backend serve to fire that event?

I just had the same problem. The solution that worked for me was to make sure I return a json model from the server that corresponds to the deleted one.
edit: returning an empty json response will suffice.
Did not work:
delete(model) {
// deleted model from db
return "Model was deleted";
}
This did work:
delete(model) {
// deleted model from db
return model;
}
or:
delete(id) {
// deleted model from db with this id
return new Model {id: id};
}

Had the same problem using Backbone 1.5.3 with Rails. I tried rudena's solution, and it works!
Here's what my controller's delete function looked like initially:
def destroy
#cell = current_user.cells.find(params[:id])
#cell.destroy
render :json => "success"
end
And here's what worked:
def destroy
#cell = current_user.cells.find(params[:id])
#cell.destroy
render :json => #cell
end

That looks good to me, exactly what I have everywhere (except I have function(model) but that shouldn't matter at all) I do know that older versions of backbone didn't use the destroy(options) but instead had destroy(success, failure). Can you make sure you have the latest version.

Had this problem come up with my UI as well. Upon DELETE, the API came back with an empty 200 response.
What's happening is, jQuery expects a json response body, but when the response comes back empty, json parsing fails and the error callback is triggered.
My solution was to override the Model's sync method:
var MyModel = Backbone.Model.extend({
// Fix for empty DELETE response
sync: function(method, model, options) {
if (method === 'delete') {
options.dataType = 'html';
}
Backbone.sync.call(this, method, model, options);
}
});
This works because options is passed to jQuery's ajax call and we're instructing jQuery not to expect json.

Related

How to get a Backbone Model attribute after fetch?

I know that a fetch is asynchronous and it needs to use "success" in fetch.
But what if I want to use the data out of the success?
I wanna to get the user ID and to use it in a model "Note".
authedUser.fetch({
success: function(){;
window.uid = authedUser.get("id");
}
But if I try to do this console.log(uid); not in success I get undefined.
You should be able to access updated model from success callback.
Like this:
authedUser.fetch({
success: function(model){;
window.uid = model.get("id");
}
When your new models/collections are registered the "change" event is triggered.
So you can use
MyModel.on("change", function() {
MyModel.get('wtv');
});

Restangular put requests.. how and why?

If I have a resource, e.g.
var resource = Restangular.all('things');
and I have json object that I want to post to the API
jsonObj = {
someVar: "x",
anotherVar: "y"
}
I can simply do
resource.post(jsonObj).then( ...etc... )
Now if I update the model on the clientside and want to save the changes, why can I not do:
resource.put(thingId, updatedJsonObj)
I'm having trouble getting my head around the demos around on the internet, as they all appear to need to do a get request before they can do a put? Which seems odd. It's worth mentioning that I am using Restangular in a SERVICE, not in a controller or directive. My service has a variable allMyThings which is the result of resource.getList() and I use that in various places in the application
Actually, if you take one item in the collection returned by getList(), you can use .save() on it, and it will call PUT method.
angular.module('demo').controller('DemoCtrl', function (myList) {
// myList is populated by Restangular.all('...').getList();
var item = myList[0];
item.name = 'foo';
item.save() // this one did a PUT :)
.then(function (res) {
// ...
});
});
See it in the docs.
NOTE :
Restangular will use the id property as id for PUT, DELETE, etc. calls.
If you want to change that behaviour, use this in module config :
RestangularProvider.setRestangularFields({
id: "_id"
});

detect when a backbone collection has been fetched (Backbone 1.0.0)

There's a new behaviour in the latest version of Backbone (1.0.0 in which the reset event is no longer triggered by default after fetching a Collection.
http://backbonejs.org/#changelog
Renamed Collection's "update" to set, for parallelism with the similar
model.set(), and contrast with reset. It's now the default updating
mechanism after a fetch. If you'd like to continue using "reset", pass
{reset: true}.
The problem is that I want to capture the event when the collection has been finally fetched (pretty common case, indeed!)
I could listen to add, remove and change event, but if the collection is empty I don't know how to catch the event.
So, what would be the new, recommended way to catch when the collection request has finalized, or is it passing a { reset = true } the only way to achieve it???
ps: here's the original question, BTW can't catch Backbone Collection reset event
From Backbone.sync doc,
Whenever a model or collection begins a sync with the server, a
"request" event is emitted. If the request completes successfully
you'll get a "sync" event, and an "error" event if not.
For example,
var C = Backbone.Collection.extend({
url: '/echo/json/'
});
var c = new C();
c.on('sync', function() {
console.log('sync');
});
c.fetch();
And a demo http://jsfiddle.net/nikoshr/GLATm/
We can pass a method as a success handler when we call fetch on collection and as you said you just want to do something when everything[add,remove,update or reset] has happened, you can do inside this success handler.
collection.fetch({
success: function() {
// Do Something
// This is called when all add, remove and update operations have been done
}
});
Note: success handler is always executed irrespective of you have passed reset:true or not. Irrespective of your collection gets empty or not and It will be called at the last step when all the add,remove and update events have occurred.
Let me know if it does not solve your problem.
My own solution is indeed pretty simple. I already have a BaseCollection with added features, so in there I just set as default { reset: true }. The code should be something like this (my own BaseCollection has a lot of stuff that is not pertinent here):
var BaseCollection = Backbone.Collection.extend({
fetch: function(options) {
options = options || {};
options.reset = (options.reset === undefined ? true : options.reset);
// just call super.fetch
return Backbone.Collection.fetch.call(this, options);
};
});
Using promises...
// you could use promises as well
// P.S.: pardon jquery promises :)
var C = Backbone.Collection.extend({
url: '/echo/json/'
});
var c = new C();
// c.fetch() returns jqXHR object that you can listen too
$.when( c.fetch() )
.done(successFn)
.fail(failFn)
.always(alwaysFn);

Backbone JS - Model save method and error callback

I am attempting to override a models save method and set an error callback. I am using a mixture of localStorage and server side data so in the event that the app can't connect to the server, I want to save the model to local storage. Here is my model code:
var Project = Backbone.Model.extend({
urlRoot: Settings.urls.projects.project,
save: function(attributes, options){
options || (options = {});
this.set("last_updated", new Date().toISOString(), {silent: true});
options.error = function(){
console.log("Error callback");
}
return this.constructor.__super__.save.apply(this, arguments);
},
As you can see, I am attempting to set options.error within the save method and then call the super method to actually action the save. For some reason it is ignoring the function and the console log statement is not getting called. Anyone have any ideas?
Check this reference:
http://backbonejs.org/#Model-extend
You need to do something like this:
return Backbone.Model.prototype.save.call(this, attributes, options);

model.fetch always going to error callback

var mdl = Backbone.Model.extend({
defaults:{
url:'/displayPostVariables.php',
age:0
},
initialize:function(opt){
this.url = function (){
return opt.url
}
}
})
mdli = new mdl({
'name' :'rajkamal'
})
jQuery.ajaxSetup({
'beforeSend': function(xhr) {
xhr.setRequestHeader("Accept", "text/html")
}
})
mdli.fetch({
success : successcallback,
error:errorcallback
});
Ajax call is going but, always ends up with the error callback.
Looks like this post model.fetch success callback does not fire on firefox, but works on chrome but there is no javascript code in that.
Thanks.
Try also passing dataType: 'json' to the fetch.
I had the same problem with fetch only ever returning my error callback.
In the end, it was because I had not specified an id in the object on the server like this:
{"title":"The Green Mile ","author":"Stephen King","img":"green_mile.jpg","id":2}
I think Backbone expects certain properties to be present in the JSON, though I was unable to find any documentation about this. The way I solved it was to do model.save() and to look at the object that was being saved.
For reference, I had the same issue because of an unsafe method incorrectly injecting NaN into the json response
{"progress":NaN}
which failed to be correctly parsed and forced the error callback
I had this issue, and it was due to using single quotes instead of double quotes to surround attributes and values in the API's JSON response.
Specify the url outside of defaults
= Backbone.Model.extend({
url : "/displayPostVariables.php",
defaults:{
},
validation: {
}
});

Resources