Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getting backbone.js to run a function after constructing a Collection?

I may be completely missing something here, but I have the following:

  • a Model which encapsulates 'all' the data (all JSON loaded from one URL)
  • the model has one (or more) Collections which it is instantiating with the data it got on construction
  • some code which I want to run on the Collection when the data is initialized and loaded

My question is about the composed Collection. I could do this outside the scope of the Collection, but I'd rather encapsulate it (otherwise what's the point of making it a 'class' with an initializer etc).

  1. I thought I could put that code in the initialize() function, but that runs before the model has been populated, so I don't have access to the models that comprise the collection (this.models is empty).

  2. Then I thought I could bind to an event, but no events are triggered after initialization. They would be if I loaded the Collection with a fetch from its own endpoint, but I'm not doing that, I'm initializing the collection from pre-existing data.

My question: How to get initialize code to run on the Collection immediately after it is initialized with data (i.e. this.models isn't empty).

Is it possible to do this without having to get 'external' code involved?

Okay here is the demo code, perhaps this will explain things better.

var Everything = Backbone.Model.extend({
    url: "/static/data/mydata.json",
    parse: function(data)
    {
        this.set("things", new Things(data.things, {controller: this}));
    }
});

var Thing = Backbone.Model.extend({
});

var Things = Backbone.Collection.extend({
  model: Thing,
  initialize: function(data, options)
  {
      // HERE I want access to this.models. 
      // Unfortunately it has not yet been populated.
      console.log("initialize");
      console.log(this.models);
      // result: []

      // And this event never gets triggered either!
      this.on("all", function(eventType)
      {
          console.log("Some kind of event happend!", eventType);
      });
  }
});

var everything = new Everything();
everything.fetch();

// Some manual poking to prove that the demo code above works:

// Run after everything has happened, to prove collection does get created with data
setTimeout(function(){console.log("outside data", everything.get("things").models);}, 1000);
// This has the expected result, prints a load of models.


// Prove that the event hander works.
setTimeout(function(){console.log("outside trigger", everything.get("things").trigger("change"));}, 1000);
// This triggers the event callback.
like image 247
Joe Avatar asked Feb 03 '12 23:02

Joe


1 Answers

Unfortunately for you the collection gets set with data only after it was properly initialized first and models are reset using silent: true flag which means the event won't trigger.

If you really wanted to use it you can cheat it a bit by delaying execution of whatever you want to do to next browser event loop using setTimeout(..., 0) or the underscore defer method.

initialize: function(data, options) {

     _.defer(_.bind(this.doSomething, this));
},

doSomething: function() {

    // now the models are going to be available
}
like image 96
Tom Tu Avatar answered Sep 28 '22 01:09

Tom Tu