2012-08-02 64 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。

相關問題