Backbone: 在模型中对集合建模的最佳方法是什么?

创建于 2010-11-04  ·  11评论  ·  资料来源: jashkenas/backbone

我的团队正在使用一个有趣的数据模式。 基本上我们拥有的是一个具有名称和版本以及属于它的项目数组的文档。 项目本身没有与它们关联的 ID,因为它们属于更大的模型,但可以从主文档中添加/编辑/删除项目。 该模型看起来像这样:
{
名称:“测试”,
版本:1,
项目 : [
{名称:“项目1”,
位置:0},
{名称:“项目2”,
位置:1}]
}

为模型中的底层项目使用集合会很棒,但是每当集合更新时,模型应该使用它的 url 回发到服务器。 在 Backbone 中建模的最佳方法是什么? 如果需要更多信息,我很乐意在要点中发布更多信息。

question

最有用的评论

@eranation :不,应该几乎相同。 使用这种模式时,我喜欢将items排除在我的属性哈希之外,这样我就不必让它们保持同步。 这要求您将items对象从响应中提取出来进行解析,然后将其添加回进行序列化(见下文)。 除此之外,您可能希望将@rsim放在initialize中的逻辑放在constructor方法中,并使用on而不是bind (这是半弃用的)。

我发现在可能的情况下,让属性只是一个浅散列(没有嵌套的集合、模型等)要容易得多。

var Document = Backbone.Model.extend({
  constructor: function() {
    this.items = new ItemSet(null, {document: this});
    this.items.on('change', this.save, this);
    Backbone.Model.apply(this, arguments);
  },
  parse: function(resp) {
    this.items.set(resp.items, {parse: true, remove: false});
    delete resp.items;
    return resp;
  },
  toJSON: function() {
    var attrs = _.clone(this.attributes);
    attrs.items = this.items.toJSON();
    return attrs;
  }
});
var ItemSet = Backbone.Collection.extend({
  model: Item,
  initialize: function(models, options) {
    this.document = options.document;
  }
});
var Item = Backbone.Model.extend({
  // access document with this.collection.document
});
var document1 = new Document({
  name: "Test",
  version: 1,
  items: [
    {name : "Item 1", position : 0},
    {name : "Item 2", position : 1}
  ]
});

这似乎甚至适用于深度嵌套的模式。 (见文档

所有11条评论

我想说你有两个主要选择......第一个是将项目保留为香草属性。 Backbone 在属性更改时使用深度相等检查,因此如果更新了内部项目,文档将知道它。

另一种选择是将项目从文档中拉出,并将它们作为自己的模型附加到粘在文档上的集合内(我们在 DocumentCloud 中按照这些方式做了一些事情)。 例如(粗略地说):

var Document = Backbone.Model.extend({
  initialize: function() {
    this.items = new ItemSet();
    this.items.bind('change', this.save);
  }
});

其中任何一个都适合您吗?

我还建议将“文档”属性添加回 Document 对象,该对象可以在需要时从项目中访问:

var Document = Backbone.Model.extend({
  initialize: function() {
    this.items = new ItemSet(this.get('items'), {document: this});
    this.items.bind('change', this.save);
  }
});
var ItemSet = Backbone.Collection.extend({
  initialize: function(models, options) {
    this.document = options.document;
  }
});
var Item = Backbone.Model.extend({
  // access document with this.collection.document
});
var document1 = new Document({
  name: "Test",
  version: 1,
  items: [
    {name : "Item 1", position : 0},
    {name : "Item 2", position : 1}
  ]
});

我相信将项目的更改事件绑定到文档保存是缺失的部分。 尽管如此,将文档添加到 ItemSet 看起来也很有帮助。 我们今天会试试这个,我会让你们知道结果如何。

这很有效。 我们现在遇到的最大问题是 mongoid。 谢谢你们的帮助。

我将如何一次保存所有项目? 我不想在每次更改项目时都发出请求,但我想通过对用户操作的单个请求将它们全部保存。 我正在考虑在保存文档并更新文档的“项目”属性时收集所有内容。 这是一个很好的解决方案吗?

只要您的项目在文档中设置,那么当您执行 document.save() 时,项目也将被发送到服务器。

但是假设我在运行时将一个项目添加到集合 document1.items 中,它也不会自动添加到 document1 的“items”属性中。 因此,如果我然后执行 document1.save(),我添加到集合中的新模型将不会发送到服务器。 我看不到集合的更改如何在通过保存发送的模型属性中传播。

所以,这里是我们处理它的方式:文档有一个默认的 items 数组。 在初始化时,在重载的 set 方法中,我从属性创建了一个新的项目集合并将其设置在文档上。

class Document extends Backbone.Model
  defaults:
    items: []

  set: (attrs, options) ->
    items = attrs['items']
    if _( items ).isArray()
      if _( items ).isEmpty()
        attrs['items'] = new DocumentItemsCollection
        newItem = new Item
        attrs['items'].add(newItem, { silent: true })
      else
        attrs['items'] = new DocumentItemsCollection items

此时,您只需使用“get”、“set”、“add”和“remove”处理项目集合方法。 你不会弄乱点符号。 我什至在我的 Document 类上有名为 addItem 和 deleteItem 的方法来触发文档本身的更改事件。 当您对文档执行 save() 时,它会在您的项目集合上调用 toJSON。

老实说,这只是我们文档的一个简单案例,我们还有更深层次的子文档。 处理如此复杂的主干,并在模型上重载几种方法,是一个真正的大麻烦。 我们现在正在考虑在未来用 sproutcore 替换主干。

如果您必须处理非常复杂的文档,那么我建议您查看 ExtJS 或 sproutcore。 Backbone 非常适合具有简单模型的小型项目,但当对象/交互开始增加时,它很快就会崩溃。

对于 1.0,是否有任何新的“最佳实践”?

@eranation :不,应该几乎相同。 使用这种模式时,我喜欢将items排除在我的属性哈希之外,这样我就不必让它们保持同步。 这要求您将items对象从响应中提取出来进行解析,然后将其添加回进行序列化(见下文)。 除此之外,您可能希望将@rsim放在initialize中的逻辑放在constructor方法中,并使用on而不是bind (这是半弃用的)。

我发现在可能的情况下,让属性只是一个浅散列(没有嵌套的集合、模型等)要容易得多。

var Document = Backbone.Model.extend({
  constructor: function() {
    this.items = new ItemSet(null, {document: this});
    this.items.on('change', this.save, this);
    Backbone.Model.apply(this, arguments);
  },
  parse: function(resp) {
    this.items.set(resp.items, {parse: true, remove: false});
    delete resp.items;
    return resp;
  },
  toJSON: function() {
    var attrs = _.clone(this.attributes);
    attrs.items = this.items.toJSON();
    return attrs;
  }
});
var ItemSet = Backbone.Collection.extend({
  model: Item,
  initialize: function(models, options) {
    this.document = options.document;
  }
});
var Item = Backbone.Model.extend({
  // access document with this.collection.document
});
var document1 = new Document({
  name: "Test",
  version: 1,
  items: [
    {name : "Item 1", position : 0},
    {name : "Item 2", position : 1}
  ]
});

这似乎甚至适用于深度嵌套的模式。 (见文档

@akre54谢谢,这是一个很好的例子,非常感谢

此页面是否有帮助?
0 / 5 - 0 等级

相关问题

rubiii picture rubiii  ·  12评论

jashkenas picture jashkenas  ·  7评论

alundiak picture alundiak  ·  7评论

miguelpayet picture miguelpayet  ·  9评论

cueedee picture cueedee  ·  3评论