10

多数のモデルを含むバックボーン コレクションがあります。

モデルに特定の属性が設定されて保存されるたびに、大量の計算が開始され、UI が再レンダリングされます。

しかし、一度に複数のモデルに属性を設定し、それらがすべて設定された後にのみ保存と再レンダリングを実行できるようにしたいと考えています。もちろん、1 回の操作で複数の http リクエストを作成したくはありませんし、インターフェースを 10 回再レンダリングする必要もありません。

Backbone.Collection で、どのモデルが hasChanged() を持っているかを解決し、それらを json としてまとめてバックエンドに送信する save メソッドを見つけたいと思っていました。その後、コレクションのイベントによって再レンダリングがトリガーされる可能性があります。そのような幸運はありません。

これはかなり一般的な要件のように思えるので、なぜ Backbone が実装しないのか疑問に思っています。これは、複数のものを単一のエンドポイントに保存する RESTful アーキテクチャに反しますか? もしそうなら、だから何?1000 個の小さなアイテムを保持するために 1000 回のリクエストを行うのは現実的ではありません。

では、すべてのモデルを反復処理し、変更されたすべてのモデルの json を構築してバックエンドに送信する独自​​の save メソッドで Backbone.Collection を拡張する唯一のソリューションはありますか? または、誰かがよりきちんとした解決策を持っていますか (または、何かが足りないだけです!)?

4

3 に答える 3

4

これを処理するためのいくつかのメソッドで Backbone.Collection を拡張することになりました。

saveChangeMethod は、Backbone.sync に渡されるダミー モデルを作成します。モデルからバックボーンの同期メソッドが必要とするのは、その url プロパティと toJSON メソッドだけなので、これを簡単にノックアップできます。

内部的には、モデルの toJSON メソッドはその属性のコピー (サーバーに送信される) のみを返すため、モデルの配列を返すだけの toJSON メソッドを喜んで使用できます。Backbone.sync はこれを文字列化して、属性データだけを提供します。

成功すると、saveChanged はコレクションでイベントを発生させ、1 回処理します。バッチのモデルのいずれかで変更された属性ごとに、特定のイベントを 1 回発生させるコードを少し追加しました。

Backbone.Collection.prototype.saveChanged = function () {
    var me = this,
        changed = me.getChanged(),
        dummy = {
            url: this.url,
            toJSON: function () {
                return changed.models;
            }
        },
        options = {
            success: function (model, resp, xhr) {
                for (var i = 0; i < changed.models.length; i++) {
                    changed.models[i].chnageSilently();
                }
                for (var attr in changed.attributes) {
                    me.trigger("batchchange:" + attr);
                }
                me.trigger("batchsync", changed);
            }
        };
    return Backbone.sync("update", dummy, options);
}

次に必要なのは、コレクションの getChanged() メソッドだけです。これは、変更されたモデルの配列と、変更された属性にフラグを付けるオブジェクトの 2 つのプロパティを持つオブジェクトを返します。

Backbone.Collection.prototype.getChanged = function () {
    var models = [],
        changedAttributes = {};
    for (var i = 0; i < this.models.length; i++) {
        if (this.models[i].hasChanged()) {
            _.extend(changedAttributes, this.models[i].changedAttributes());
            models.push(this.models[i]);
        }
    }
    return models.length ? {models: models, attributes: changedAttributes} : null;
}

これは、バックボーンの「変更されたモデル」パラダイムの使用目的のわずかな悪用ですが、バッチ処理の要点は、モデルが変更されたときに何も起こらないようにする (つまり、イベントが発生しないようにする) ことです。

したがって、{silent: true} をモデルの set() メソッドに渡す必要があるため、バックボーンの hasChanged() を使用して保存待ちのモデルにフラグを立てるのが理にかなっています。もちろん、他の目的でモデルを黙って変更していた場合、これは問題になります。collection.saveChanged() はこれらも保存するため、別のフラグを設定することを検討する価値があります。

いずれにせよ、この方法で保存する場合、バックボーンがモデルが変更されていないと (変更イベントをトリガーせずに) 認識していることを確認する必要があるため、モデルが変更されていないかのように手動で操作する必要があります。変更されました。saveChanged() メソッドは、変更されたモデルを繰り返し処理し、モデルでこの changeSilently() メソッドを呼び出します。これは基本的に、トリガーのない Backbone の model.change() メソッドです。

Backbone.Model.prototype.changeSilently = function () {
    var options = {},
    changing = this._changing;
    this._changing = true;
    for (var attr in this._silent) this._pending[attr] = true;
    this._silent = {};
    if (changing) return this;

    while (!_.isEmpty(this._pending)) {
        this._pending = {};
        for (var attr in this.changed) {
        if (this._pending[attr] || this._silent[attr]) continue;
        delete this.changed[attr];
        }
        this._previousAttributes = _.clone(this.attributes);
    }
    this._changing = false;
    return this;
}

使用法:

model1.set({key: value}, {silent: true});
model2.set({key: value}, {silent: true});
model3.set({key: value}, {silent: true});
collection.saveChanged();

RE。RESTfulness.. コレクションのエンドポイントに PUT を実行して、レコードの「一部」を変更するのは適切ではありません。技術的には、PUT はコレクション全体を置き換える必要がありますが、アプリケーションで実際にコレクション全体を置き換える必要が生じるまでは、実用的なアプローチを喜んで採用します。

于 2012-09-06T18:09:34.400 に答える
1

この種の動作を実現するために、新しいリソースを定義して、それを と呼ぶことができますMyModelBatch

Arrayモデルのを消化して適切なアクションを実行できる新しいリソースをサーバー側に実装する必要があります: CREATEUPDATEおよびDESTROY.

また、モデルの配列であるModel1 つの属性urlと、id.

再レンダリングについては、各モデルごとに 1 つのビューを作成することをお勧めします。これにより、モデルが変更されたのと同じ数のレンダリングが行われますが、重複することなく詳細な再レンダリングが行われます。

于 2012-09-05T19:20:58.643 に答える