0

(免责声明:这个问题比标题所暗示的要简单得多!)

我的程序架构中再次出现一个问题,即监听模型的更改。

我已经设置了一些集合(很像 in 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
}

如果同一用户被保存两次,则事件会被多次添加/触发。有没有更好的模式呢?

事件是否应该通过集合冒泡并以这种方式处理?

这是一个实际的例子(我最感到羞耻的一个)

$("#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开始,事件对象发生了一些变化,这使得我上面的代码无法工作,请参阅jQuery 1.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 回答