Получение backbone.js для запуска функции после создания коллекции? - PullRequest
5 голосов
/ 04 февраля 2012

Я могу здесь что-то упустить, но у меня есть следующее:

  • Модель, которая инкапсулирует «все» данные (все JSON загружаются с одного URL)
  • модель имеет одну (или несколько) коллекций, для которых она создает экземпляр с данными, полученными при построении
  • некоторый код, который я хочу запустить в Коллекции, когда данные инициализируются и загружаются

У меня вопрос о сочиненной коллекции. Я мог бы сделать это вне рамок Коллекции, но я бы предпочел инкапсулировать его (иначе какой смысл делать его «классом» с инициализатором и т. Д.).

  1. Я думал, что мог бы поместить этот код в функцию initialize(), но он запускается до заполнения модели, поэтому у меня нет доступа к моделям, составляющим коллекцию (this.models пусто ).

  2. Тогда я подумал, что могу привязаться к событию, но никакие события не запускаются после инициализации. Они были бы, если бы я загрузил коллекцию с fetch из ее собственной конечной точки, но я этого не делаю, я инициализирую коллекцию из уже существующих данных.

Мой вопрос: Как заставить инициализировать код для запуска в Собрании сразу после того, как он инициализирован данными (т.е. this.models не пусто).

Возможно ли это сделать без необходимости вовлечения внешнего кода?

Хорошо, вот демонстрационный код, возможно, это объяснит лучше.

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.

Ответы [ 2 ]

7 голосов
/ 04 февраля 2012

К сожалению, для вас коллекция устанавливается с данными только после того, как она была правильно инициализирована первой, а модели сбрасываются с использованием флага silent: true, что означает, что событие не сработает.

Если вы действительно хотите его использовать, вы можете немного его обмануть, отложив выполнение того, что вы хотите сделать, до следующего цикла событий браузера, используя setTimeout (..., 0) или метод подчеркивания defer,

initialize: function(data, options) {

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

doSomething: function() {

    // now the models are going to be available
}
0 голосов
/ 06 декабря 2016

Копаем это старый вопрос.У меня была похожая проблема, и я получил некоторую помощь в создании этого решения:

Расширяя функцию set, мы можем узнать, когда данные коллекции были преобразованы в реальные модели.(Set вызывается из .add и .reset, что означает, что он вызывается во время основной функции, создающей экземпляр класса Collection AND из выборки, независимо от reset или set в параметрах выборки. Погружение в основной источник с комментариямиздесь помогло следование потоку функций)

Таким образом, мы можем контролировать, когда и как мы получим уведомление, не взламывая поток выполнения.

var MyCollection = Backbone.Collection.extend({
  url: "http://private-a2993-test958.apiary-mock.com/notes",
  initialize: function () {
    this.listenToOnce(this, 'set', this.onInitialized)
  },

  onInitialized:function(){
    console.log("collection models have been initialized:",this.models )
  },

  set: function(models,options){
    Backbone.Collection.prototype.set.call(this, models, options);
    this.trigger("set");
  }
})

//Works with Fetch!
var fetchCollection= new MyCollection()
fetchCollection.fetch();

//Works with initializing data
var colData = new MyCollection([
        {id:5, name:'five'},
        {id:6, name:'six'},
        {id:7, name:'seven'},
        {id:8, name:'eight'}
     ])

//doesn't trigger the initialized function
colData.add(new Backbone.Model({id:9,name:'nine'};

Примечание. Если мы не используем.listenToOnce, тогда мы также будем вызывать onInitialized каждый раз, когда модель добавляется или изменяется в коллекции.

...