【问题标题】:In Meteor how can I create a generic event handler?在 Meteor 中如何创建通用事件处理程序?
【发布时间】:2012-08-02 10:13:03
【问题描述】:

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

错误

未捕获的类型错误:无法调用未定义的方法“btn_events”

但是,如果我以这种方式定义事件处理程序并以这种方式调用它,它就可以工作。

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 并在任何页面上形成的漂亮按钮而在我的网站上复制代码。如果我能把它抽象出来,那么我应该能够在所有页面上为我正在呈现的任何允许数据输入的集合提供一个显示表单类型的按钮。同样,这也导致能够为所有表单创建一个表单处理程序,然后通过对模型的操作将它们绑定到控制器。

有什么想法吗?

【问题讨论】:

    标签: javascript meteor dom-events


    【解决方案1】:

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

    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 个不同的模板定义,那么您仍然只需要将处理程序绑定到单个模板。

    【讨论】:

    • 这很好用。我正在弃用我的旧代码。我认为在过去的某个时候,这不适用于 Meteor 的早期版本。我最初的解决方案已经使用了一年多。
    【解决方案2】:

    我觉得你把事情复杂化了。为什么不这样做?

    Template.someTemplate.events({
      'click .button': buttonClicked
    });
    
    function buttonClicked(evt) {
      // DRY code to handle a button being clicked
    }
    

    这具有适当的分离平衡:您的事件处理程序定义一次,但您可以告诉每个模板您希望其按钮侦听某个事件。如果这还不够好,你可以进一步抽象它:

    Template.someTemplate.events(genericEvents);
    

    如果您愿意,甚至可以将 genericEvents 与该模板的特定事件合并。

    【讨论】:

      【解决方案3】:

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

      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 将事件连接到一个集合,并通过客户端/服务器共享数据模型将其抽象出来,以便与 Meteor 中现有的内容一起进行验证甚至访问控制。

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

      【讨论】:

        【解决方案4】:

        我在 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 (...) 中的哪一个:

        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。

        【讨论】:

          猜你喜欢
          • 2013-12-24
          • 2015-01-17
          • 1970-01-01
          • 2012-07-31
          • 2021-02-17
          • 1970-01-01
          • 2014-02-26
          • 2013-08-15
          • 1970-01-01
          相关资源
          最近更新 更多