(免责声明:这个问题比标题所暗示的要简单得多!)
我的程序架构中出现了一个重新出现的问题,它听取了对模型的更改。
我已经设置了一些集合(很像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();
}
});
答案 0 :(得分: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
});
}
见工作example
为了将一些糖放在最上面,我们可以将“检查是否存在事件”逻辑放入自定义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
});
工作example
更新JQUERY> = 1.8
从 jQuery 1.8 开始,对事件对象进行了一些更改,这使我的上述代码无法正常工作,请参阅jQuery 1.8 release notes中的摘录:
$(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);
};
答案 1 :(得分: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");
}
}