2012-08-02 9 views
6

dom要素に再利用できる汎用イベントハンドラを作成したいので、何度も何度もボイラープレートを作成する必要はありません。私はそれが分かったと思ったが、間違いがある。メテオではどうすれば汎用イベントハンドラを作成できますか?

私が抱えている問題は、イベントハンドラが必要な時とは異なる時間にバインドされていると思います。多分document.readyで? .live()メソッドでそれらをアタッチする必要があると思うところは?私はここで何を言っているのか分からないかもしれませんが。ここで

は私がしようとしているものです:

マルチページアプリケーション。

データを挿入する必要のある複数のコレクション。

挿入フォームを示すボタンコード。ここで、ページ(コントローラ)

{{> groups_insert}} 

に基づくフォームはフォームであることを示し

<button id="btnShowInsert" class="btn btn-success" rel="tooltip" title="add group"> 
    <i id="btnIcon" class="icon-plus-sign icon-white"></i> 
</button> 

テンプレート。

<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; 

は、ERROR

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タイプのボタンを持つことができます。同様に、これは、すべてのフォームのための1つのフォームハンドラを作成し、モデルへのアクションを通じてそれらをコントローラに結びつけることにつながります。

アイデア?

答えて

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

これは素晴らしい動作します。私は古いコードを非難しています。過去のある時点では、これはメテオの初期バージョンでは機能しませんでした。私の元々の解決策は1年以上経ちました。 –

3

私はあなたがものを複雑にしているように感じます。なぜこれをしないのですか?

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

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

これは分離の適切なバランスを持っている:あなたのイベントハンドラが一度定義されていますが、そのボタンがいくつかのイベントに聴きたい各テンプレートを伝えることができます。それで十分でない場合は、さらに抽象化することができます:

さらに、必要に応じて汎用イベントとそのテンプレートの特定のイベントをマージすることもできます。

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を処理するためのテンプレートイベントマップを作成する必要はありません。/routeがコレクション名に対応している限り、任意の数のハンドルバーテンプレートを作成できます。私は時々巧妙な変換をいくつか行いますが。基本的に、汎用イベントハンドラは、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 
}) 

あなたが動的にあなたがしたいB、C、またはD(...)のどちら選ぶ "A" のためのヘルパー関数を定義します

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が含まれている必要はありません。