0

バックボーンアプリには、モデルに裏打ちされたビューがあり、モデルをコレクションに保存しています。ページにはこれらのビューがいくつかあり、一度に選択できるのは1つだけです。したがって、これらのビューのコレクションを含む別のビューがあります。ユーザーがフォーカスされていないビューをクリックすると、ビューはモデルの「フォーカスされた」属性をtrueに設定します。モデルのセットは、ビュー自体によって処理される変更イベント($ elにフォーカスされたクラスを追加する)、コレクション内のすべてのビューをループし、フォーカスされているビューのフォーカスを解除するViewCollectionビューをトリガーします(クリックしたばかりのもの以外)。

適度な速度でクリックすると、これはすべてうまく機能します。ただし、非常に速くクリックすると、モデルの設定された動作に矛盾が見られます。つまり、モデルの「focused」属性をtrueに設定すると、次のクリックイベントは、そのモデルの「focused」属性がまだfalseであることを示します。

コード:

    var M = Backbone.Model.extend({
            defaults : {
                            "name" : "",
                "focused" : true
            }
    }),

    L = Backbone.Collection.extend({
            model : M
    }),

    V = Backbone.View.extend({
    events : {
        "click .button" : "focus"
    }
    initialize: function() {
      this.model.bind("change:focused", this.handleFocusChange, this)
    },
    focus: function() {
                console.log("Focus: " + this.model.get("name") + ".focused = " + this.model.get("focused"));

                if (this.model.get("focused")) {
                    return;
                }

                this.model.set({focused: true});  // triggers change event
                this.model.save(this.model);
                console.log("Focus: " + this.model.get("name") + ".focused = " + this.model.get("focused"));
            },
            unfocus: function() {
                console.log("Unfocus: " + this.model.get("name") + ".focused = " + this.model.get("focused"));
                if (!this.model.get("focused")) {
                    return;
                }

                this.model.set({focused: false});  // triggers change event
                this.model.save(this.model);
                console.log("Unfocus: " + this.model.get("name") + ".focused = " + this.model.get("focused"));
            },
            handleFocusChange: function(model, focused) {
                if (focused) {
                    console.log("Handling focus change on " + this.model.get("name") + ", " + this.model.cid);
                    this.$('.button').addClass("focused");
                } else {        
                    console.log("Handling unfocus change on " + this.model.get("nickname") + ", " + this.model.cid);
                    this.$('.button').removeClass("focused");
                }
            }
    }),

    ViewCollection = Backbone.View.extend({
    initialize : function(options) {
                _.bindAll(this, 'initViews');

                this._views = [];

                this.collection.each(this.initViews);
            },
            initViews : function(model) {
                var view = new V({
                    model : model
                });

                this._views.push(view);

                view.model.bind("change:focused", this.focusChanged, this);
            },
            focusChanged: function(changed, focused) {
                if (!focused) {
                    return;
                }

                _.each(this._views, function(view) {
                    if (view.model.id !== changed.id) {
                        view.unfocus();
                    }
                });
            }
    })

上記のログステートメントからの出力は次のとおりです。

Click
Focus: A.focused = false
Handling focus change on A, c10
Unfocus: B.focused = false
Unfocus: C.focused = false
Unfocus: D.focused = true
Handling ufocus change on D, c7
Unfocus: D.focused = false
Focus: A.focused = true  <-- good!
Click
Focus: C.focused = false
Handling focus change on C, c9
Unfocus: B.focused = false
Unfocus: A.focused = false  <-- bad!
Unfocus: D.focused = false
Focus: C.focused = true 

ご覧のとおり、最初にAをクリックし、次にCをクリックしました。変更されたイベントが発生し、ビューとコレクションの両方が適切に動作しました。ただし、2回目のクリックでは、Aの「focused」属性はtrueであるはずのときにfalseになります。繰り返しますが、これは私がビューを非常に速くクリックしたときにのみ発生します。通常の速度でクリックすると、この問題を再現できません。

どんな助けでも大歓迎です!

4

1 に答える 1

1

これは処理するのが大変ですが、セットアップを正しく理解していれば.... からの ajax 呼び出しmodel.save()が失敗しているようです。

model.save()非同期です。save 呼び出しが戻る前に、変更イベントを発生させます。保存に失敗すると、変更は取り消されます。次のいずれかまたはいくつかを試してください。

  • Firebug、Fiddler、またはその他で何が起こるかを見てください...
  • ロギング関数をsuccessまたはerrorコールバックとして配置して、どちらが起動するかを確認してください。
  • 待機パラメータ ( ) を追加してthis.model.save(this.model, {wait:true});、ロギングがどのように変化するかを確認します。
于 2012-08-01T20:59:50.773 に答える