2012-08-02 21 views
6

我想创建一个通用事件处理程序,我可以在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; 

的错误

Uncaught TypeError: Cannot call method 'btn_events' of undefined 

,如果我定义事件处理这种方式,并呼吁它这样它的工作原理。

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类型的按钮。同样,这导致可以为所有表单创建一个表单处理程序,然后通过对模型的操作将它们绑定到控制器。

任何想法?

回答

10

您可以将高级模板绑定到使用子模板创建的元素。那么你只需要做一次绑定。例如

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所不同的模板定义,所以你仍然只需要处理程序绑定到一个模板。

+1

This works great。我贬低我的旧代码。我认为在过去的某个时候,这不适用于流星的早期版本。我原来的解决方案已经过了一年多了。 – 2014-02-15 17:35:13

3

我觉得你太过于复杂了。为什么不这样做?

Template.someTemplate.events({ 
    'click .button': buttonClicked 
}); 

function buttonClicked(evt) { 
    // DRY code to handle a button being clicked 
} 

这有分离的适当的平衡:你的事件处理程序被定义一次,但你可以告诉你想要的按钮来听一些事件每个模板。如果这还不够好,您可以进一步摘要:

Template.someTemplate.events(genericEvents); 

如果你想甚至可能合并与特定事件genericEvents该模板。

1

这是我最终做的。该示例仅显示通用插入处理程序。

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。只要/路线对应于集合名称,我就可以创建任意数量的车把模板。尽管我不时进行一些棘手的转换。基本上,通用事件处理程序基于路径aka request.controller将事件连接到集合,并通过客户端/服务器共享数据模型将其抽象出来,以用于验证,甚至访问控制以及Meteor中存在的事件。

它似乎运作良好,并大大减少了我的代码库。我有几十个集合,因为我不必编写任何事件映射处理程序,因为基本CRUD已处理,但已抽象出足够多,以便我可以自定义客户端/服务器共享数据模型上的验证,安全性和其他完整性检查。

0

我在Meteor 1.0.2中遇到这个问题的方法是使用动态模板。请参阅Dan Dascalescu的canonical answerdocs

假设您有一组附加到模板“A”的通用事件,并且您想在模板“B”,“C”和“D”中利用它们。

HTML:

<template name="A"> 
    {{> Template.dynamic template=myTemplate}} 
</template> 

JS:

Template.A.events({ 
    ... your event code 
}) 

你定义一个辅助函数为 “A” 动态挑选其中的B,C,或d(...)你想包括: “C”,和 “D” 中的 “A” 现在将在 “B” 可用定义

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”不需要包含任何HTML。

相关问题