4

Similar question was already asked here How do I trigger the success callback on a model.save()?, but still no answer how to trigger events from callbacks.

So here is success callback in my code, in which I want to call addOne event to render saved Comment. Everything works well except this.addOne(receivedItem); - I can't use this in callback to trigger this event. Everywhere else - I can.

How to solve this problem?

CommentsListView = Backbone.View.extend({
    ...
    addOne: function (item) {
        var commentView = new CommentView({
            model: item
        });
        this.$el.append(commentView.render().el);
    },
    addNewComment: function (event) {
        var item = {
            post_id: this.$('#post_id').val(),
            text: this.$('#text').val()
        };
        var commentItem = new CommentItem();
        commentItem.save({'model':item}, { 
            success: function(receivedItem, response) {
                this.addOne(receivedItem); // Uncaught TypeError: Object [object Window] has no method 'addOne'.
            }
        }, this);
    }
});
Louis
  • 146,715
  • 28
  • 274
  • 320
Gediminas Šukys
  • 7,101
  • 7
  • 46
  • 59
  • 2
    Possible duplicate of [How to access the correct \`this\` / context inside a callback?](http://stackoverflow.com/questions/20279484/how-to-access-the-correct-this-context-inside-a-callback) – Bergi Nov 08 '16 at 17:09

2 Answers2

9

That happens because the success callback has a different scope, and this does not point to your view.
To quickly solve this, just make a reference to this and use it instead:

var self = this;
commentItem.save({'model':item}, { 
    success: function(receivedItem, response) {
        self.addOne(receivedItem); // works
    }
});

or you can use underscore's bind method to bind a different context to a function :

success : _.bind(function(receivedItem, response) {
    this.addOne(receivedItem); 
}, this)
gion_13
  • 41,171
  • 10
  • 96
  • 108
  • You are genius man! It works! And it will be useful for others - I spent hours to solve this (I'm not so good in javascript yet) :) – Gediminas Šukys Dec 29 '12 at 11:53
  • @MdaG are you referring to underscore's `bind` method? – gion_13 Jun 05 '13 at 22:02
  • No, I mean how can sending "this" as an additional parameter make it work? I have a knowledge gap here as I've seen it used in other code as well. – MdaG Jun 06 '13 at 11:10
  • @MdaG That's what underscore's bind function does. It takes 2 arguments : a function and an object, and returns a new function with the specified object as scope. I's similar to the standard `bind` method of functions in es5 : `var getFoo = function (){return this.foo;}.bind({foo:'bar'})`. you should probably read the docs to clear that gap :) – gion_13 Jun 06 '13 at 13:56
  • Read the docs. :) Understand bind (or do I?), but I meant your first example where you send 'this' as a third parameter to save. According to the docs it only takes two arguments. http://backbonejs.org/#Model-save – MdaG Jun 06 '13 at 20:57
  • 1
    @MdaG I'm sorry that I didn't understand what you were saying before. You are right: `model.save` only takes 2 arguments. I really can't remember how or why the third argument got in that function call (since this answer dates a while back). It is unnecessary and misleading and I apologize for that. Anyway, the thing is that the context is preserved by using a reference to `this` in the `self` variable. Updated the answer too. thx – gion_13 Jun 07 '13 at 06:21
0

This could be a late answer. but would help somebody who is looking for it. This is accessing 'this' keyword from a settimeout callback

CommentsListView = Backbone.View.extend({
...
    addOne: function (item) {
        // DO Stuff
    },
    addNewComment: _.bind(function (event) {
        setTimeout(_.bind(function(){ 
            this.addOne(/*receivedItem*/);
        }, this), 1000);
    }, this)
});
Vinnie
  • 1,053
  • 11
  • 31