【问题标题】:What's the proper way to set a parent property in Backbone?在 Backbone 中设置父属性的正确方法是什么?
【发布时间】:2012-06-18 21:39:11
【问题描述】:

我有一个 JSON 文件,它将创建我的 ParentModel 并填充子 Records 集合。

ParentModel : Backbone.Model.extend({
  initialize: function() {
    this.set({ records: new Records(this.get("records")) });
  }
});

Records 集合只是映射到 Record 模型的基本 Backbone 集合。

问题是我需要孩子知道父级,所以每个Record 模型必须有一个父级属性。所以现在我只是将它添加到初始化方法的底部:

var self = this;
this.get("records").each(function(record) {
  record.set("parent", self);
});

这很好用,但是当我创建新记录时,我宁愿不必记住包含这 4 行。

This answer 说我可以重写initialize 方法来接收额外的参数,但我不太确定如何让Backbone 自动将ParentModel 传递给重写的initialize 方法。谁能提供一个例子来说明如何做到这一点?

我听说过Backbone-relational,它可能会帮助我做我想做的事,但还要包含 23kb。如果这是更好的方法,我会考虑实施它,但如果有可用的解决方案,我更喜欢更简单的解决方案。

无论我是通过代码创建一个新的ParentModel 记录,还是它是由 JSON 提要自动创建的,这都需要工作。

【问题讨论】:

  • 我发布了一个解决方案,但在重读您的问题后,我意识到这不是您要寻找的答案。我认为没有一种解决方案不会增加代码的复杂性。但如果你真的想这样做,我认为最好的覆盖位置是 Records 集合;重写 initialize 以检查并设置父选项,然后使用 add 函数为您添加到集合中的每个新模型设置父级。
  • @Brandon 希望将记录添加到集合中。每个模型现在都有一个collection 属性,可以使用model.collection 访问可能这个提示会帮助你
  • @AnthonyChua,这在通过代码添加新记录时会起作用,但是如何确保在从 JSON 提要填充模型时使用覆盖的初始化方法?
  • @Brandon 如果您通过通常的fetch() 调用填充集合,则集合实际上只是调用resetadd 函数,具体取决于您传递的选项。即使collection.fetch 默认调用resetreset 仍将使用add 来填充集合。
  • 你能解释一下为什么你需要在每个Record 模型中引用Records 集合吗?这看起来很奇怪。

标签: backbone.js


【解决方案1】:

我通常发现将结构元素移出属性更清晰,因此我的记录和父属性位于对象上,而不是属性上。也就是说,您可以利用集合和父对象上的不同事件:

var ParentModel = Backbone.Model.extend({
    initialize: function () {
        _.bindAll(this, 'adoptOne', 'adoptAll');
        this.records = new Records();

        this.on('change:records', function () {
             this.records.reset(this.get('records'));
        });
        this.records.on('reset', this.adoptAll);
        this.records.on('add', this.adoptOne);

        this.records.reset(this.get('records'));
    },

    adoptAll: function () {
       this.records.each(this.adoptOne);
    },
    adoptOne: function (model) {
        model.parent = this;
    }
});

一些测试:

var p = new ParentModel({
    name: "I am the parent",
    records: [{id: 1}, {id: 2}]
});

p.records.add({id: 3});

p.records.each(function (child) {
    console.log(child.get('id')+' '+child.parent.get('name'));
});

p.set({records: [{id: 4}]});

p.records.each(function (child) {
    console.log(child.get('id')+' '+child.parent.get('name'));
});

还有一个小提琴http://jsfiddle.net/sPXaZ/

【讨论】:

    【解决方案2】:

    为了清楚起见,这里是您的一个需求的摘要(可以在问题 cmets 中找到):

    例如,如果我想居中定位一个 Record 元素,我需要 知道viewbox有多宽。唯一知道的方法就是知道 最广泛的记录元素是什么。父对象可以告诉我 通过对其子元素进行排序。

    在我看来,您的模型必须处理显示问题; Backbone 中的显示由 Views 处理。所以,我猜你可以创建一个同时收听ParentModelRecords 的视图。

    var RecordView = Backbone.View.extend({
      initialize: function() {
        this.collection.on('sync', this.render, this);
      }
      render: function() {
        var widest = this.model.get('width');
      }
    });
    
    var view = new RecordView({model: ParentModel, collection: Records});
    

    而且,在我看来,这不是ParentModel 来处理它在屏幕上的宽度,而是它自己的视图。在这里介绍两个 View 似乎是重点。

    但我没有完整的图片,所以,如果我错了,请给我更多你想要做的样本。

    【讨论】:

    • 我意识到模型不应该处理显示问题,但实际上width 是模型本身的一部分。这些模型映射到存储在数据库中的 SVG 元素,但我明白你在说什么。感谢您的回答。
    • 即使width 是您的Model 的一部分,我还是强烈建议您按原样使用Backbone 框架。以一种无法想象的方式扭曲一个框架可能会让您感到头疼。我的建议是:将ModelCollection 属性转换为正确的ViewModel 负责 HTTP 请求,View 负责显示。你不觉得会更容易吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-18
    • 1970-01-01
    • 2022-11-08
    • 1970-01-01
    • 2012-01-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多