Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/430.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 侦听数组中对象的更改,而不嵌套事件侦听器_Javascript_Jquery_Event Bubbling_Event Listener - Fatal编程技术网

Javascript 侦听数组中对象的更改,而不嵌套事件侦听器

Javascript 侦听数组中对象的更改,而不嵌套事件侦听器,javascript,jquery,event-bubbling,event-listener,Javascript,Jquery,Event Bubbling,Event Listener,(免责声明:这个问题比标题所暗示的要简单得多!) 在我的程序体系结构中,我有一个反复出现的问题,就是监听对模型的更改 我设置了一些集合(很像Backbone.js),它们只是围绕数组构建的轻量级类。集合是模型的集合。当用户对模型进行更改时,我总是以可怕的嵌套事件结束。这是我试图避免的典型、简单的场景: $("#user-details").on("click", "#save", onSaveClick); function onSaveClick() { var giv

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

在我的程序体系结构中,我有一个反复出现的问题,就是监听对模型的更改

我设置了一些集合(很像
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
}
如果同一用户保存两次,则会多次添加/触发事件。有更好的模式吗

该事件是否应该在集合中不断涌现并以这种方式处理

下面是一个实际的例子(我最为惭愧的例子)


您只需检查
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
    });
}
$("#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");
   }
}
见工作


为了在上面添加一些糖分,我们可以将“检查事件是否存在””逻辑放入自定义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对象发生了一些更改,这使得我的上述代码无法工作,请参见以下摘录:

$(element).data(“事件”):在1.6版中,jQuery将其 来自用户数据的内部数据,以防止名称冲突。 然而,有些人使用内部未记录的“事件” 数据结构,所以我们仍然可以通过
.data()
。现在在1.8中删除了它,但是您仍然可以访问 用于调试目的的事件数据,通过
$。\u数据(元素,“事件”)
。 请注意,这不是受支持的公共接口;实际数据 结构可能在不同版本之间发生不兼容的更改

因此,我在这里发布了上述示例的更新版本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);
};

我同意嵌套侦听器有点奇怪——毕竟,您已经在保存侦听器中了,只是为了按钮单击而不是模型对象

我想我应该重写代码如下:

// 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
    });
}
$("#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");
   }
}

虽然您所建议的是一种更干净的方法,但我的问题是由于save的异步性。因此,听众的依赖性无处不在。不确定数据流回的确切位置,但基本目标似乎是只在一个位置将render()注册为save()回调。因此,也许您可以将其注册到save()方法本身?该模型用于多个视图,但这不是一个坏主意。我可以通过回调实现类似的效果。可能比使用listenersYep更好,传入回调以激活()是我考虑的另一件事。逻辑稍微不那么集中,但它更灵活。我接受尼尔森的答案只是因为它回答了原始问题的“核心”。但是谢谢你的时间Ethan这里有一些非常好的想法,你是否考虑过使用一个预构建的框架,比如knockout.js,将数据和UI绑定在一起。我是一个新的皈依者,我印象深刻@是的,我非常喜欢使用Knockout.js,它看起来很棒。问题是工作不会给我时间去学习它和移植现有的代码。我认为knockout可能会将我编写的代码减半,并解决70%的bug。我可能会在我自己的时间里学习它,并在我有能力的时候提出这个想法。对于任何在jQuery>=1.8中有问题的人,请使用:$。\u data((用户),“events”)嗨,Nelson,你写的那块漂亮的糖在jQuery 1.82中不起作用。我想不出为什么要应用我注意到的更改above@CrimsonChin对于jQuery>=1.8,它应该是
$。\u数据($(用户).get(0),'events')
或只是
$。\u数据(用户,'events')