在构建集合后让backbone.js运行一个函数?

发布于 2025-01-02 12:32:08 字数 1904 浏览 3 评论 0原文

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

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

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

  1. 我认为我可以将该代码放入 initialize() 函数中,但该代码在填充模型之前运行,因此我无权访问构成集合的模型(< code>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.

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

尝蛊 2025-01-09 12:32:08

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

如果你真的想使用它,你可以通过使用 setTimeout(..., 0) 或下划线 defer 方法。

initialize: function(data, options) {

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

doSomething: function() {

    // now the models are going to be available
}

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
}
水波映月 2025-01-09 12:32:08

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

通过扩展 set 函数,我们可以知道集合的数据何时已转换为真实模型。 (Set 从 .add 和 .reset 中调用,这意味着它在实例化 Collection 类的核心函数期间被调用,并且从 fetch 中调用,无论 fetch 中的 resetset深入研究主干注释源代码并遵循功能流程在这里有所帮助)

这样我们就可以控制何时/如何收到通知而无需破坏执行流程。

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。 EM>

Digging this an old question. I had a similar problem, and got some help to create this solution:

By extending the set function we can know when the collection's data has been converted to real models. (Set gets called from .add and .reset, which means it is called during the core function instantiating the Collection class AND from fetch, regardless of reset or set in the fetch options. A dive into the backbone annotated source and following the function flow helped here)

This way we can have control over when / how we get notified without hacking the execution flow.

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'};

Note: If we dont use .listenToOnce, then we will also get onInitialized called every time a model is added to or changed in the collection as well.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文