Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone.js binding a change event to a collection inside a model

I'm pretty new to Backbone so excuse me if this question is a little obvious. I am having problems with a collection inside of a model. When the collection changes it doesn't register as a change in the model (and doesn't save).

I have set up my model like so:

var Article = Backbone.Model.extend({

   defaults: {
       "emsID" :  $('html').attr('id')
   },

   initialize: function() { 
       this.tags = new App.Collections.Tags();
   },

   url: '/editorial_dev.php/api/1/article/persist.json'
});

This works fine if I update the tags collection and manually save the model:

this.model.tags.add({p : "a"});

this.model.save();

But if the model is not saved the view doesn't notice the change. Can anyone see what I am doing wrong?

like image 289
Ad Taylor Avatar asked May 25 '11 15:05

Ad Taylor


2 Answers

initialize: function() { 
    this.tags = new App.Collections.Tags();
    var model = this;
    this.tags.bind("change", function() {
        model.save();
    });
},

Bind to the change event on the inner collection and just manually call .save on your outer model.

like image 175
Raynos Avatar answered Sep 21 '22 05:09

Raynos


This is actually an addendum to @Raynos answer, but it's long enough that I need answer-formatting instead of comment-formatting.

  1. Clearly OP wants to bind to change and add here, but other people may want to bind to destroy as well. There may be other events (I'm not 100% familiar with all of them yet), so binding to all would cover all your bases.

    remove also works instead of destroy. Note that both remove and destroy fire when a model is deleted--first destroy, then remove. This propagates up to the collection and reverses order: remove first, then destroy. E.g.

    model event      :      destroy
    model event      :      remove
    collection event :      destroy
    collection event :      remove
    
  2. There's a gotcha with custom event handlers described in this blog post.

    Summary: Model-level events should propagate up to their collection, but can be prevented if something handles the event first and calls event.stopPropagation. If the event handler returns false, this is a jQuery shortcut for event.stopPropagation(); event.preventDefault();

  3. Calling this.bind in a model or collection refers to Underscore.js's bind, NOT jQuery/Zepto's. What's the difference? The biggest one I noticed is that you cannot specify multiple events in a single string with space-separation. E.g.

    this.bind('event1 event2 ...', ...)
    

    This code looks for the event called event1 event2 .... In jQuery, this would bind the callback to event1, event2, ... If you want to bind a function to multiple events, bind it to all or call bind once for each event. There is an issue filed on github for this, so this one will hopefully change. For now (11/17/2011), be wary of this.

like image 22
Eric Hu Avatar answered Sep 21 '22 05:09

Eric Hu