0

(免責事項:この質問は、タイトルが示唆するよりもはるかに単純です!)

モデルに対する変更をリッスンするという問題がプログラムアーキテクチャで繰り返し発生します。

Backbone.js配列を中心に構築された軽量クラスであるコレクションをいくつか設定しました(のように)。コレクションはモデルのコレクションです。ユーザーがモデルに変更を加えると、恐ろしいネストされたイベントが発生し続けます。これは、私が避けようとしている典型的な単純なシナリオです。

$("#user-details").on("click", "#save", onSaveClick);

function onSaveClick()
{       
    var givennames = $("#givenname").val(),

    // Get the model from the collection
    var user = users.get($(this).attr("data-id"));

    // set the property
    user.set("GivenNames", givennames);

    // listen for the save event
    $(user).on("save", function(){
        // Alert the view
    });

    user.save();    // save event triggers a "save" event on the model
}

同じユーザーが2回保存されると、イベントは複数回追加/発生します。これにはもっと良いパターンがありますか?

イベントはコレクション全体で泡立ち、おそらくそのように処理されるべきでしょうか?

これが実際の例です(私が最も恥ずかしい例です)

$("#user-devices").on("click", ".device button", function(){

            var button = $(this),
                deviceId = $(this).closest(".device").attr("data-id"),
                device = userDevices.get(deviceId);


            $(device).on("activate", function(event, device){

                button.removeClass("btn-danger").addClass("btn-success")

                $("#activation-dialog").modal("show");
            })

            if (device.get("Active") === "1")
            {
                $("#reactivation-warning-dialog").modal("show");
                $("#reactivation-warning-dialog .btn-primary").on("click", function(){
                    device.activate();
                });

            }
            else
            {
                device.activate();  
            }
        });
4

2 に答える 2

1

save次のように、イベントがすでにバインドされているかどうかを確認できます。その場合は、再度バインドしないでください。

// if no 'save' event already binded
if (!$(user).data('events') || !$(user).data('events').save) { 
    // listen for the save event
    $(user).on("save", function(){
        // Alert the view
    });
}

実例を見る


砂糖を上に置くために、「イベントが存在するかどうかを確認する」ロジックをカスタムjquery疑似セレクターに組み込むことができます。これは、次のように定義されます。

$.expr[':'].hasEvent = function(obj, idx, meta, stack) {
    return ($(obj).data('events') != undefined 
            && $(obj).data('events')[meta[3]] != undefined);
};

次に、次のように使用できます。

$(user).not(":hasEvent(save)").on("save", function(){
     // Alert the view
});

実例_


JQUERYの更新>=1.8

jQuery 1.8以降、eventsオブジェクトにいくつかの変更が加えられ、上記のコードが機能しなくなりました。jQuery1.8リリースノートからの抜粋を参照してください。

$(element).data( "events"):バージョン1.6では、jQueryは、名前の衝突を防ぐために、内部データをユーザーのデータから分離しました。ただし、一部の人々は内部の文書化されていない「イベント」データ構造を使用していたため、を介してそれを取得できるようにしました .data()。これは1.8で削除されましたが、を介してデバッグ目的でイベントデータにアクセスできます$._data(element, "events")。これはサポートされているパブリックインターフェイスではないことに注意してください。実際のデータ構造は、バージョンごとに互換性がないように変更される場合があります。

したがって、ここでは、上記の例のjQuery>=1.8の更新バージョンを投稿します。

保存イベントがすでにバインドされているかどうかを確認します。その場合は、再度バインドしないでください。

// if no 'save' event already binded
if (!$._data(user, 'events') || !$._data(user, 'events').save) { 
    // listen for the save event
    $(user).on("save", function(){
        // Alert the view
    });
}

そして、カスタムjquery疑似セレクター:

$.expr[':'].hasEvent = function(obj, idx, meta, stack) {
    return ($._data(obj, 'events') != undefined 
            && $._data(obj, 'events')[meta[3]] != undefined);
};
于 2012-11-12T09:46:15.733 に答える
0

ネストされたリスナーが少し奇妙であることに同意します。結局のところ、モデルオブジェクトではなく、ボタンをクリックするだけで、既に保存リスナーになっています。

コードを次のように書き直したいと思います。

$("#user-devices").on("click", ".device button", function(){

    var button = $(this),
        deviceId = $(this).closest(".device").attr("data-id"),
        device = userDevices.get(deviceId);

    if (device.get("Active") === "1")
    {
        $("#reactivation-warning-dialog").modal("show");
        $("#reactivation-warning-dialog .btn-primary").on("click", device.activate);

    }
    else
    {
        device.activate();
    }
});

//in the device "class"
{ 
   ...
   ...

   activate: function() {
     //persist and stuf.

     //on success...
     this.render();
   }

   render: function() {
      button.removeClass("btn-danger").addClass("btn-success");
      $("#activation-dialog").modal("show");
   }
}
于 2012-11-12T09:53:39.247 に答える