6

言葉にするのが非常に難しいため、解決策を見つけるのが難しい、非常に単純な問題があると思います。設定:

  • PathCollection はパスの Backbone.Collection です
  • Path は、NodeCollection (Backbone.Collection) と EdgeCollection (Backbone.Collection) を含む Backbone.Model です。

PathCollection をフェッチすると

paths = new PathCollection()
paths.fetch()

明らかに、パスはインスタンス化されます。ただし、パスが属性ハッシュからサブモデルをインスタンス化できるようにする場所がありません。私は本当にパースを使うことができませんよね?基本的に、モデルがインスタンス化されて属性が設定されたときに、モデルのエントリポイントを探しています。それには何らかの慣習が必要だと思います。

4

1 に答える 1

25

そのため、サブモデルとサブコレクション(ネストされたデータ)の使用parse()とインスタンス化と入力に関するいくつかの回答を書きました。set()ただし、私が見た多くのプラクティスのいくつかを統合する、本当に包括的な回答は見たことがありません。私はたくさん書くと少し取り乱す傾向があるので、少し脱線するかもしれませんが、これは同様の問題を経験している人々にとって役立つかもしれません.

これを行うにはいくつかの方法があります。を使用しparse()ます。を操作することset()は別です。あなたの中でこれらをインスタンス化することinitialize()は別のものです。パスモデルの外ですべてを行うことは別です(例path = new Path(); path.nodes = new NodeCollection();など)

2番目の考慮事項はこれです。ノードとエッジ コレクションをモデル属性にしますか? それともモデルのプロパティ?

ああ、たくさんの選択肢。自由度は高いのですが、「正しい方法」を判断するのが難しくなることがあります。

これはよくあることなので、長い記事を作成して 1 つずつ説明します。この回答を更新し続けるので、しばらくお待ちください。

モデルの外でそれを行う - シンプルでわかりやすい

これは通常、特定のモデルまたはコレクションでのみ必要な場合に、ネストされたモデルおよびコレクションを追加する簡単な方法です。

path = new PathModel();

path.nodes = new NodeCollection();
path.edge = new EdgeCollection();

// Continue to set up the nested data URL, etc.

これは最も簡単な方法であり、定義を必要としない 1 回限りのモデルやコレクションを扱う場合に適しています。これらのモデルは、何かを行う前にこのオブジェクトを構築するメソッド (ビュー メソッドなど) で簡単に生成できますが。

initialize()すべてのモデルでサブモデル/コレクションを使用する

特定のモデルのすべてのインスタンスが常にサブモデルまたはサブコレクションを持つことがわかっている場合、設定する最も簡単な方法はinitialize()関数を利用することです。

たとえば、Path モデルを取り上げます。

Path = Backbone.Model.extend({
    initialize: function() {
        this.nodes = new NodeCollection();
        this.paths = new PathCollection();

        // Maybe assign a proper url in relation to this Path model
        // You might even set up a change:id listener to set the url when this
        // model gets an id, assuming it doesn't have one at start.
        this.nodes.url = this.id ? 'path/' + this.id + '/nodes' : undefined;
        this.paths.url = this.id ? 'path/' + this.id + '/paths' : undefined;
    }
});

これで、サブコレクションを取得できpath.nodes.fetch()、正しい URL にルーティングされます。簡単です。

parse()サブデータのインスタンス化と設定に使用

おそらく、すべてのモデルにノードとエッジ コレクションがあると想定したくない場合は、もう少し注意が必要です。fetch()がそのようなデータを送り返す場合にのみ、ネストされたモデル/コレクションが必要になる場合があります。これは、 を使用parse()すると便利な場合です。

parse()問題は、任意の json サーバー応答を受け取り、モデルset()関数に渡す前に適切に名前空間を作成して処理できることです。したがって、モデルまたはコレクションの生データが含まれているかどうかを確認し、応答を親モデルの属性に減らす前に処理できます。

たとえば、サーバーから次のような応答が返されることがあります。

// Path model JSON example with nested collections JSON arrays
{
    'name':'orange site',
    'url':'orange.com',
    'nodes':[
        {'id':'1', 'nodeColor':'red'},
        {'id':'2', 'nodeColor':'white'},
        {'id':'3', 'nodeColor':'blue'}
    ],
    'edge':[
        {'id':'1', 'location':'north'},
        {'id':'1', 'location':'south'},
        {'id':'1', 'location':'east'}
    ]
}

デフォルトのparse()バックボーンでは、これを取り込んで、パス モデルの属性「ノード」と「エッジ」にデータ (コレクションではない) の array() を割り当てます。したがってparse()、これを適切に処理するようにします。

parse: function(response) {

    // Check if response includes some nested collection data... our case 'nodes'
    if (_.has(response, 'nodes')){

         // Check if this model has a property called nodes
        if (!_.has(this, 'nodes')) {  // It does not...
            // So instantiate a collection and pass in raw data
            this.nodes = new NodeCollection(response.nodes);
        } else {
            // It does, so just reset the collection
            this.nodes.reset(response.nodes);
        }

        // Assuming the fetch gets this model id
        this.nodes.url = 'path/' + response.id + '/nodes';  // Set model relative URL

        // Delete the nodes so it doesn't clutter our model attributes
        delete response.nodes;
    }

    // Same for edge...

    return response;
}

カスタマイズset()した を使用して、サブデータを処理することもできます。どちらが優れているかを何度も行ったり来たりした後、操作しset()たり実行したりした後、もっとparse()使いたいと思いましたparse()。しかし、私はこれに関する他の人々の考えにオープンです。

set()サブデータの処理に使用する

データをparse()取得するか、オプションを使用してデータをコレクションに渡すことに依存していますが、parse:true一部の人々は関数を変更することを優先しset()ます。繰り返しますが、正しい選択があるかどうかはわかりませんが、これがどのように機能するかです。

set: function(attributes, options) {
    // If we pass in nodes collection JSON array and this model has a nodes attribute
    // Assume we already set it as a collection
    if (_.has(attributes, 'nodes') && this.get("nodes")) {
        this.get('nodes').reset(attributes.nodes);
        delete attributes.nodes;
    } else if (_.has(attributes, 'nodes') && !this.get('nodes')) {
        this.set('nodes', new NodeCollection(attributes.nodes));
        delete attributes.nodes;
    }

    return Backbone.Model.prototype.set.call(this, attributes, options);
}

したがって、すでに属性があり、それがコレクションである場合は、それをreset()使用します。属性があってもそれがコレクションでない場合は、それをインスタンス化します。プロトタイプに渡す前に、サブデータの JSON 配列をコレクションに正しく変換することが重要ですset()。バックボーンは、JSON 配列をコレクションとして解釈せず、まっすぐな配列のみを取得します。

つまり、簡単に言えば、どのように行動するかについて多くのオプションがあります。initialize()繰り返しますが、現在、何かが常にこれらのサブモデル/コレクションを持っていることがわかっているparse()場合と、状況が呼び出しで可能なネストされたデータのみを必要とする場合に、組み合わせて使用​​することを好みfetch()ます。

あなたのその質問について... (そうそう、質問がありました)

Path がさまざまな方法でハッシュからサブモデルをインスタンス化できるようにすることができます。私はあなたに 4 を与えました。必要に応じて parse を使用できます。fetch()パス モデルまたは pathCollection になることがわかっている場合は...pathCollection.fetch({parse:true})規則はありますか? 多分そうでないかもしれません。モデル/コレクションを使用すると思われるコンテキストに応じて、さまざまな方法を組み合わせて使用​​するのが好きです。

私は、これらのプラクティスのいくつかと、それらが良いか悪いかについて議論することに非常にオープンです. それらは、私が Stack で見つけた多くのソリューションであり、自分の作業習慣に組み込まれており、私にとってはうまく機能しているようです. :-)

コーヒーを飲みながら背中を軽くたたいてください。それは長い読み物でした。

于 2012-09-10T14:42:55.023 に答える