0
votes

Trying to understand the insides of backbone.js (Todos App) framework by adding some extra functionalities, my Todos App triggers an collection.add event on both collections, the original TodoList and my own UnsavedList

This is what I did:

Adding an 'Mark All Done' button to document trough _.template that checks all unchecked checkboxes without saving changes to the server.

Adding an 'Save ({unsaved collection length})' button to document trough _.template.

To accomplish this, I keep track of the 'savedState' of all models in TodoList

// inside TodoList
hasUnsaved: function() {
  return this.filter(function(todo) {
    var isEqual = _.isEqual(todo.savedAttributes, todo.attributes);
    return !isEqual;
  })
},

Declaring and instantiating UnsavedList:

// inside window
window.UnsavedList = Backbone.Collection.extend({

  model: Todo,

  initialize: function() {
      this.bind('add', this.addHandler)
  },

  addHandler: function() {
      alert('added')
  }
});

window.UnsavedTodos = new UnsavedList;

As in the original sample, the add event is bound to addOne Handler.

// inside AppView
...
initialize: function() {
  Todos.bind('add', this.addOne);
  ...
}

Listens to 'Mark All Done' Button click to invoke markAllDone which in turn triggers 'change:allDone':

// inside AppView
markAllDone: function() {
    Todos.each(function(todo) {
        todo.set({ done: true });
    })
    Todos.trigger('change:allDone');

},

... and 'change:allDone' invokes:

// inside AppView
checkSaved: function() {
    this.$('#todo-controls #button-saved').html(this.buttonSavedTemplate({
        saved: function() {
            var list = Todos.hasUnsaved();
            _.each(list, function(todo) {
                UnsavedTodos.add(todo);
            })
            return list.length;
        }
    }));
},

If you look at the iterator of my template object, I'm adding all unsaved models to my UnsavedList. But strangely enough TodoList also listens to this exact 'add' event at what all unsaved models show up duplicated on the page.

Why is that, even tough I 'added' to UnsavedList only.

Thoughts ?

1

1 Answers

0
votes

Even though I could have lived with an { silent: true } option, I was too curious about this behavior and figured out myself looking in the source code:

Every time a model is added to an collection, the model itself triggers the add-event. And in my case both, the TodoList as well as UnsavedList are listening to 'add'

Here's the code snipped from backbone.js:

// inside _add
if (!options.silent) model.trigger('add', model, this, options);

To walk around this (guess I want to keep my event flow), I just store a cloned copy of the model like this:

UnsavedTodos.add(_.clone(todo), { silent: false });

I'm sure it's much easier to accomplish this using nested collections or whatever handling the same model instead of clones, I managed keeping track of my unsaved (cloned) models by means of events, triggered each time after a save, create or destroy.

This is my completed modified Todos App