Backbone: モデル内でコレクションをモデル化するための最良の方法は何ですか?

作成日 2010年11月04日  ·  11コメント  ·  ソース: jashkenas/backbone

私のチームは、興味深いデータスキーマを使用しています。 基本的に、私たちが持っているのは、名前とバージョン、およびそれに属するアイテムの配列を持つドキュメントです。 アイテム自体は、より大きなモデルに属しているため、IDが関連付けられていませんが、アイテムはメインドキュメントから追加/編集/削除できます。 モデルは次のようになります。
{{
名前:「テスト」、
バージョン:1、
アイテム:[
{名前: "アイテム1"、
位置:0}、
{名前: "アイテム2"、
位置:1}]
}

モデルの基になるアイテムにコレクションを使用するのは素晴らしいことですが、コレクションが更新されるたびに、モデルはそのURLを使用してサーバーにポストバックする必要があります。 バックボーンでこれをモデル化する最良の方法は何ですか? さらに情報が必要な場合は、要点をもっと投稿させていただきます。

question

最も参考になるコメント

@eranation :いいえ、ほとんど同じである必要があります。 このパターンを使用するときは、属性ハッシュからitems除外するのが好きなので、それらの同期を維持する必要はありません。 これには、解析のために応答からitemsオブジェクトを引き出し、シリアル化のために追加し直す必要があります(以下を参照)。 それとは別に、 @ rsimconstructorメソッドにinitializeに入れたロジックを、代わりにbind代わりにonを使用することをお勧めします。 (これは半非推奨です)。

可能であれば、属性を浅いハッシュ(ネストされたコレクションやモデルなどを含まない)にする方がはるかに簡単だと思います。

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件

主な選択肢は2つあると思います... 1つ目は、アイテムをバニラ属性のままにすることです。 バックボーンは、属性が変更されたときに詳細な等価性チェックを使用するため、内部アイテムが更新された場合、ドキュメントはそれを認識します。

もう1つのオプションは、アイテムをドキュメントから引き出し、ドキュメントに貼り付けられたコレクション内に、それ自体でモデルとして添付することです(DocumentCloudでこれらの行に沿って何かを行います)。 例(大まかに言えば):

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

それらのどちらかがあなたのためにうまくいきますか?

また、アイテムから必要なときにアクセスできるDocumentオブジェクトに「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にドキュメントを追加することも非常に役立つようです。 今日はこれを試してみて、どうなるかを皆さんにお知らせします。

これはうまくいきました。 私たちが今抱えている最大の問題はモンゴイドです。 助けてくれてありがとう。

すべてのアイテムを一度に保存するにはどうすればよいですか? アイテムが変更されるたびにリクエストを送信したくはありませんが、ユーザーのアクションに対する1回のリクエストですべてを保存したいと思います。 ドキュメントが保存されたときにすべてを収集し、ドキュメントの「アイテム」属性を更新することを考えていました。 それは良い解決策ですか?

アイテムがドキュメントに設定されている限り、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を検討することをお勧めします。 バックボーンは、単純なモデルを使用する小さなプロジェクトに最適ですが、オブジェクト/インタラクションが増加し始めるとすぐに崩壊します。

1.0の場合、これに関する新しい「ベストプラクティス」はありますか?

@eranation :いいえ、ほとんど同じである必要があります。 このパターンを使用するときは、属性ハッシュからitems除外するのが好きなので、それらの同期を維持する必要はありません。 これには、解析のために応答からitemsオブジェクトを引き出し、シリアル化のために追加し直す必要があります(以下を参照)。 それとは別に、 @ rsimconstructorメソッドにinitializeに入れたロジックを、代わりにbind代わりにonを使用することをお勧めします。 (これは半非推奨です)。

可能であれば、属性を浅いハッシュ(ネストされたコレクションやモデルなどを含まない)にする方がはるかに簡単だと思います。

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 評価