5

我可能在这里完全遗漏了一些东西,但我有以下几点:

  • 封装“所有”数据的模型(从一个 URL 加载的所有 JSON)
  • 该模型有一个(或多个)集合,它正在使用它在构建时获得的数据进行实例化
  • 初始化和加载数据时我想在集合上运行的一些代码

我的问题是关于组合的集合。我可以在 Collection 范围之外执行此操作,但我宁愿封装它(否则将其设为具有初始化程序等的“类”有什么意义)。

  1. 我以为我可以将该代码放入initialize()函数中,但该代码在填充模型之前运行,因此我无权访问包含集合的模型(this.models为空)。

  2. 然后我以为我可以绑定到一个事件,但是初始化后没有触发任何事件。如果我从它自己的端点加载集合,它们将是fetch,但我没有这样做,我正在从预先存在的数据初始化集合。

我的问题:如何在使用数据初始化后立即在 Collection 上运行初始化代码(即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.
4

2 回答 2

7

不幸的是,只有在首先正确初始化集合并使用silent: true标志重置模型后,才能使用数据设置集合,这意味着事件不会触发。

如果你真的想使用它,你可以通过使用 setTimeout(..., 0) 或下划线defer方法延迟执行你想做的任何事情到下一个浏览器事件循环来欺骗它。

initialize: function(data, options) {

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

doSomething: function() {

    // now the models are going to be available
}
于 2012-02-04T01:56:18.127 回答
0

挖掘这是一个老问题。我有一个类似的问题,并得到了一些帮助来创建这个解决方案:

通过扩展 set 函数,我们可以知道集合的数据何时转换为真实模型。(Set 是从 .add 和 .reset 调用的,这意味着它是在实例化 Collection 类和从 fetch 的核心函数期间调用的,无论在 fetch 选项中reset还是set在 fetch 选项中。深入了解主干注释源并遵循函数流程有助于此处)

通过这种方式,我们可以控制何时/如何获得通知,而无需破解执行流程。

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

于 2016-12-06T16:47:29.440 回答