107
this.model.save({
  success: function(model, response){
    console.log('success');
  },
  error: function(){
    console.log('error');
  }
})

The model is correctly posted to the server which handles the save, but the success callback is not fired. Do I need to send something back from the server ?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Running Turtle
  • 12,360
  • 20
  • 55
  • 73

8 Answers8

123

The first argument of save is the attributes to save on the model:

this.model.save( {att1 : "value"}, {success :handler1, error: handler2});
Julien
  • 9,216
  • 4
  • 37
  • 38
  • 9
    I'm a tad confused - (1)I thought that backbone always sent the whole model back during save (that it's not possible to send partial model updates). So what is the purpose of the attribute name-values? (2) What if you just want to save the model after performing some .set()s - why the attribute list? (3) In the docs, the attribute list param is shown as optional. Can you clarify? Thanks. – UpTheCreek Sep 21 '11 at 13:19
  • 7
    You can do a bunch of "set" with your attributes and then do a save without any attributes. All attributes of the model are always sent to the server. Save with attributes is just a shortcut to set+save . – Julien Sep 23 '11 at 15:18
  • 5
    As silly as it seems this is exactly what it does, shame it's poorly documented. – Kevin Mar 06 '12 at 09:58
  • 51
    It appears in my testing that the success and error callbacks do not get fired if you do not pass something for the "attributes" parameter. This seems to contradict the documentation... model.save([attributes], [options]) would indicate that attributes are optional. When I include attributes or null for the attributes, my success and error callbacks are fired. When I do not include anything for the attributes, the callbacks are NOT fired. – Kevin Jun 10 '12 at 17:53
  • 6
    checked the source code of backbone.js [http://backbonejs.org/docs/backbone.html ]. it seems that the attr is mandatory.. if only 'option' is provided the functions assumes it to be the 'attr' and messes up the call – Kumaresan Dec 07 '12 at 10:34
  • #Kevin did you do at least a set before the save without attributes? – Julien Dec 30 '12 at 02:49
  • 2
    Only adding an empty object also works. `this.model.save({},{success: function(model, response, options) {...` works for me. – driechel Jan 09 '13 at 15:24
  • 3
    If you use null for the first argument everything works as designed. All attributes are sent to the server and the success callback works. – Paul Oliver Jul 21 '13 at 22:47
58

For some unknown reason, none of the above method worked for me. The api only was not hit in my case.

But later while searching on this, I bumped into this link, where some one had tried null instead of {} as the first parameter.

this.model.save(null, {
    success: function (model, response) {
        console.log("success");
    },
    error: function (model, response) {
        console.log("error");
    }
});

so, this worked for me. Hope this helps you too.

Yasser Shaikh
  • 46,934
  • 46
  • 204
  • 281
38

Your server must return a JSON object. If the response is not a JSON object, the callbacks will not fire.

If for success your server doesn't return a JSON object, perform a save with dataType:"text" option, like this:

this.model.save([],{
 dataType:"text",
 success:function() {},
 error:function() {}
});

With this option it will not be waiting for a JSON in response, but a text, and thus the callback will be launched.

Igor G.
  • 6,955
  • 6
  • 26
  • 26
  • Holy crap thank you. This was driving me bonkers. Would be awesome if this were documented in the Backbone docs somewhere, – Tobias J Apr 16 '15 at 04:05
  • this saved my ass. I was using res.json({success:result}) with Express 4, and that was still giving me problems. Perhaps I need to do: res.json({"success":"result"}) or something... – Alexander Mills Jun 29 '15 at 19:11
  • Thanks a lot! This made my day. – alcfeoh Sep 13 '18 at 19:13
11

You may use underscore lib as follows as backbone already depends upon this. Remember first argument of save must either have attributes or you may just pass {} in case you want to save model itself.

this.model.save({}, _.bind(function(model, response){
  //Do whatever you want e.g.
  this.collection.add(model)
}, this))
Pradeep Kumar Mishra
  • 10,839
  • 4
  • 25
  • 26
9

so im a little confused - do i still need to pass in all attributes in order for me to call a save event? what if my model is large.. i dont wish to set every property manually

im calling model.save and attempting to do the following:

this.model.save(
    {
        success: function (model, response) {
            console.log('model saved');
        }
    });

ok just to answer my own question incase anyone finds this post, i did the following which works:

this.model.save({ id: this.model.get('id') },
    {
        success: function (model, response) {
            console.log("success");
        },
        error: function (model, response) {
            console.log("error");
        }
    });

EDIT: I couldn't reply to you for some reason, but I can edit

but you don't have to set id: this.model.get('id') you can just pass a blank object because a blank attribute just won't extend attributes, does nothing:

this.model.save({}, {
    success: function (model, response) {
        console.log("success");
    },
    error: function (model, response) {
        console.log("error");
    }
});
nackjicholson
  • 4,557
  • 4
  • 37
  • 35
nologo
  • 5,918
  • 3
  • 36
  • 50
4

The following is the code that i am using for backbone model save.

this.model.save(model,{
   success:function(model){
       console.log("Saved Successfully");
   },
   error:function(model){
       console.log("Error");
   }
});

Cheers

Roy M J

Roy M J
  • 6,926
  • 7
  • 51
  • 78
  • it's somewhat distracting to pass a local `model` to a `this.model`.. `model` should be `attributes`, which are set and saved along with everything in `this.model` – dansch Jun 08 '15 at 19:23
  • @Funkodebat: Yes.:).. I actually thought this was similar to normal jquery-ajax, but in Backbone, the first parameter would be the model. Not necessarily passing it, but rather getting the corresponding one. It is quite disturbing indeed..:( – Roy M J Jun 09 '15 at 09:05
  • Well, the truth is, no, you don't pass the model when calling save. the first argument of save is extra attributes that you can set before calling save. It'd be like calling `model.set(model.toJSON()); model.save()`. there's no reason to set a model to what the model is set to.. it's the epitome of redundant to pass a model to itself when saving. – dansch Jun 09 '15 at 16:09
  • 2
    @Funkodebat I've rejected your changes to this 3 year old answer as they radically changed the author's response. This is not the intent of the edit/moderation system. If the answer is no longer relevant or appropriate vote it down and write a new one. The moderation tools are for fixing grammar, formatting, spelling and capitalisation - not for adjusting the answers of other users. – reach4thelasers Jun 09 '15 at 16:13
  • This whole question should be deleted.. i've never seen a SO post with so many wrong answers. – dansch Jun 09 '15 at 16:14
  • 2
    The community would disagree with you. Its a highly voted question with a highly-voted top-answer. The question seems relevant to the community. If you disagree with anything use the vote-down button. Its not your place to dictate what questions and answers have a right to be on this site, and its certainly not your place to modify the answers of other users to the point that their meaning is drastically changed. – reach4thelasers Jun 09 '15 at 16:21
1

For those that want to save a model, without updating the attributes, you can do the following:

model.once("sync", function(model, response, options){
    //
});
model.once("error", function(model, response, options){
    //
});
model.save();
timborden
  • 1,470
  • 4
  • 18
  • 24
1

In you initialize function, bind the sync method to a method you define (onSaveSuccess)

            initialize: function (options) {
                    this.model.on('sync', _.bind(this.onSaveSuccess, this));
},
            onSaveSuccess: function() {
                console.log('saved');
                this.render();
            },

This way, any time you run this.model.save(), it will run the onSaveSuccess function as a callback if your sync is successful

Peter Graham
  • 2,467
  • 2
  • 24
  • 29