我想创建一个通用事件处理程序,可以在dom元素上重用,这样就不必一遍又一遍地编写样板。我以为我知道了,但是我遇到了错误。
我遇到的问题是,我认为事件处理程序的绑定时间与我所需的时间不同。也许在document.ready
?我认为需要在哪里附加.live()
方法?尽管我可能不知道我在说什么。
这是我想要做的:
多页应用程序。
需要在其中插入数据的多个集合。
显示插入形式的按钮代码。
<button id="btnShowInsert" class="btn btn-success" rel="tooltip" title="add group">
<i id="btnIcon" class="icon-plus-sign icon-white"></i>
</button>
基于页面显示表单的模板(控制器)
{{> groups_insert}}
这里是表格。
<template name="groups_insert">
{{#if acl_check}}
{{> alert}}
< p>
< form class="form-horizontal well hide" id="insert">
<fieldset>
< div class="control-group">
< label class="control-label" for="name">Name</label>
< div class="controls">
< input type="text" class="input-xlarge" id="name" name="name">
< /div>
< /div>
< div class="form-actions well">
< button id="btnReset" type="reset" class="btn btn-large">Reset</button>
< button id="btnSubmit" type="button" class="btn btn-primary btn-large">Submit</button>
< /div>
< /fieldset>
< /form>
< /p>
{{/if}}
< /template>
这里是客户端代码,用于实现在页面上显示表单的按钮。
Template.groups.events[ Meteor.eventhandler.btn_events('#btnShowInsert') ] = Meteor.eventhandler.make_btn_show_insert_form_click_handler();
这是我的通用事件处理程序:
var EventHandler = Base.extend({
btn_events: function(selector) {
return 'click ' + selector; //, keydown '+selector+', focusout '+selector;
},
make_btn_show_insert_form_click_handler: function(){
//var click = options.click || function () {};
return function (event) {
if (event.type === "click") {
event.stopPropagation();
event.preventDefault;
try{
if ($('#btnIcon').hasClass('icon-plus-sign') ) {
$('#btnIcon').removeClass('icon-plus-sign');
$('#btnIcon').addClass('icon-minus-sign');
} else {
$('#btnIcon').removeClass('icon-minus-sign');
$('#btnIcon').addClass('icon-plus-sign');
}
$('#insert').slideToggle('slow', 'swing');
} catch(error) {
Alert.setAlert('Error', 'Critical Error: ' + error, 'alert-error');
}
}
}
},
});
Meteor.eventhandler = new EventHandler;
错误
未捕获的TypeError:无法调用未定义的方法'btn_events'
BUT,如果我以这种方式定义事件处理程序并以这种方式调用它,那么它将起作用。
Template.groups.events[ btn_events('#btnShowInsert') ] = make_btn_show_insert_form_click_handler();
var btn_events = function (selector) {
return 'click ' + selector; //, keydown '+selector+', focusout '+selector;
};
var make_btn_show_insert_form_click_handler =
function () {
//var click = options.click || function () {};
console.log( Meteor.request.controller );
return function (event) {
if (event.type === "click") {
event.stopPropagation();
event.preventDefault;
try{
if ($('#btnIcon').hasClass('icon-plus-sign') ) {
$('#btnIcon').removeClass('icon-plus-sign');
$('#btnIcon').addClass('icon-minus-sign');
} else {
$('#btnIcon').removeClass('icon-minus-sign');
$('#btnIcon').addClass('icon-plus-sign');
}
$('#insert').slideToggle('slow', 'swing');
} catch(error) {
Alert.setAlert('Error', 'Critical Error: ' + error, 'alert-error');
}
}
}
};
问题我不想为了实现一个可以在任何页面上显示slideToggle
和表格的漂亮按钮而在我的网站上复制代码。如果我可以抽象它,那么我应该能够在所有页面上为我正在渲染的任何允许数据输入的集合设置一个Show Form类型的按钮。同样,这导致能够为所有表单创建一个表单处理程序,然后通过对模型的操作将它们绑定到控制器。
有什么想法吗?
您可以将高级模板绑定到使用子模板创建的元素。然后,您只需要做一次绑定。例如
HTML:
<template name="settings">
{{> login_settings }}
{{> account_settings }}
{{> data_settings }}
</template>
<template name="login_settings">
<btn class="slideToggle">Slide me for login!</btn>
</template>
<template name="account_settings">
<btn class="slideToggle">Slide me for account!</btn>
</template>
<template name="data_settings">
<btn class="slideToggle">Slide me for data!</btn>
</template>
JavaScript:
Template.settings.events {
'click .slideToggle': function() {
var clickedElement = event.target;
// add/remove CSS classes to clicked element
}
};
因此,如果最终在设置下创建10个不同的模板定义,那么您仍然只需要将处理程序绑定到单个模板。
我觉得您太过复杂了。为什么不这样做?
Template.someTemplate.events({
'click .button': buttonClicked
});
function buttonClicked(evt) {
// DRY code to handle a button being clicked
}
这具有适当的分隔平衡:您的事件处理程序定义一次,但是您可以告诉每个模板您希望其按钮监听某些事件。如果那还不够好,您可以进一步抽象它:
Template.someTemplate.events(genericEvents);
如果需要,甚至可以将通用事件与该模板的特定事件合并。
这是我最后要做的。该示例仅显示通用插入处理程序。
var EventHandler = Base.extend({
btnClickHandler: function(){
return function (event) {
event.preventDefault();
Meteor.eventhandler[event.currentTarget.id](event);
}
},
insert: function(event){
event.preventDefault();
var params = $('#insert-form').toJSON();
try{
window[Meteor.request.controller.capitalise()]['validateParams'](params);
var ts = new Date();
params.client_updated = ts;
var has_popup = params.has_popup;
delete params.has_popup;
window[Meteor.request.controller.capitalise()]['insert'](params, function(error, _id){
if(error){
Alert.setAlert('Error', error, 'alert-error', true, has_popup);
} else {
Alert.setAlert('Success', 'Record successfully created.', 'alert-success', true, has_popup);
$("#insert-form").reset();
Meteor.flush();
}
});
} catch(error) {
Alert.setAlert('Error', error, 'alert-error', true, params.has_popup);
}
}
});
Meteor.eventhandler = new EventHandler;
现在,我只需要创建把手模板,而无需进行任何重要的javascript编码即可处理通用事件并按如下所示进行连接。
$(document).on("click", '#print', Meteor.eventhandler.btnClickHandler());
$(document).on("click", '#insert', Meteor.eventhandler.btnClickHandler());
$(document).on("click", '#remove', Meteor.eventhandler.btnClickHandler());
$(document).on("click", '#removeSubField', Meteor.eventhandler.btnClickHandler());
$(document).on("click", '#insertSubField', Meteor.eventhandler.btnClickHandler())
$(document).on("click", '#update', Meteor.eventhandler.btnClickHandler());
$(document).on("click", '#updateSubField', Meteor.eventhandler.btnClickHandler());
$(document).on("click", "#toggleActive", Meteor.eventhandler.btnClickHandler());
$(document).on("click", "#toggleChild", Meteor.eventhandler.btnClickHandler());
现在,我不必编写任何模板事件映射来处理基本的CRUD。我可以创建任意数量的车把模板,只要/ route对应于集合名称即可。尽管我有时会进行一些棘手的转换。基本上,通用事件处理程序根据路由(也称为request.controller)将事件连接到一个集合,并通过客户端/服务器共享数据模型将其抽象化,以进行验证,甚至与流星中现有的访问控制进行访问控制。
它似乎运行良好,并且大大减少了我的代码库。我有几十个集合,我不需要编写任何事件映射处理程序,因为可以处理基本的CRUD,但是足够抽象,可以在客户端/服务器共享数据模型上自定义验证,安全性和其他健全性检查。
我在Meteor 1.0.2中针对此问题采取的方法是使用动态模板。参见Dan Dascalescu的canonical answer和docs。
假设您在模板“ A”上具有一组通用事件,并且希望在模板“ B”,“ C”和“ D”中利用它们。
HTML:
<template name="A">
{{> Template.dynamic template=myTemplate}}
</template>
JS:
Template.A.events({
... your event code
})
您为“ A”定义了一个辅助函数,该函数动态地选择您要包括的B,C或D(...):
Template.A.helpers({ // dynamically insert a template
myTemplate: function(){
if (...) return 'B'; // return a string with the name of the template to embed
if (...) return 'C';
if (...) return 'D';
}
})
“ A”中定义的事件现在将在“ B”,“ C”和“ D”中可用。
请注意,模板“ A”不需要包含任何HTML。