2012-08-02 21 views
6

Voglio creare un gestore di eventi generico che posso riutilizzare su elementi dom in modo da non dover scrivere più volte la piastra della caldaia. Pensavo di aver capito, ma sto ricevendo errori.In Meteor, come posso creare un gestore di eventi generico?

Il problema che sto avendo è che penso che i gestori di eventi siano legati in un momento diverso da quello di cui ho bisogno. Forse al document.ready? Dove penso di doverli allegare con il metodo .live()? Anche se forse non ho idea di cosa sto parlando qui.

Ecco quello che sto cercando di fare:

applicazione multi pagina.

Più raccolte in cui è necessario inserire i dati.

Codice pulsante per mostrare il modulo di inserimento.

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

modello che mostra il modulo in base alla pagina (controllore)

{{> groups_insert}} 

Qui è la forma.

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

Ecco il codice client per implementare il pulsante che mostra il modulo sulla pagina.

Template.groups.events[ Meteor.eventhandler.btn_events('#btnShowInsert') ] = Meteor.eventhandler.make_btn_show_insert_form_click_handler(); 

Ecco il mio gestore di eventi generico

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; 

L'ERRORE

Uncaught TypeError: Cannot call method 'btn_events' of undefined 

MA, se io definisco il gestore di eventi in questo modo e lo chiamo in questo modo funziona .

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'); 
     } 
    } 
    } 
}; 

Il problema Io non voglio avere a replicare il codice tutto il mio sito al fine di implementare un pulsante bello che può slideToggle e modulo a qualsiasi pagina. Se potessi ottenerlo in modo astratto, dovrei essere in grado di avere un tipo di pulsante Show Form su tutte le pagine per qualsiasi raccolta che sto rendendo disponibile per l'immissione dei dati. Inoltre, questo porta a essere in grado di creare un gestore di moduli per tutte le forme e quindi legarle al controllore attraverso un'azione al modello.

Qualche idea?

risposta

10

È possibile associare un modello di livello superiore a elementi creati con modelli figlio. Quindi devi eseguire il binding una sola volta. Per esempio

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

Quindi, se si finisce per creare 10 differenti definizioni di modello in Impostazioni quindi è ancora sufficiente associare il gestore per un singolo modello.

+1

Questo funziona benissimo. Sto deprecando il mio vecchio codice. Penso che a un certo punto nel passato questo non ha funzionato con una versione anticipata di Meteor. La mia soluzione originale aveva più di un anno. –

3

Mi sembra che tu stia complicando le cose. Perché non farlo?

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

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

Questo ha il giusto equilibrio di separazione: il vostro gestore di eventi è definito una volta, ma si può dire ogni modello che si desidera i suoi pulsanti per ascoltare qualche evento. E se questo non è abbastanza buona, si può ulteriormente è astratta:

Template.someTemplate.events(genericEvents); 

e forse anche unire genericEvents con eventi specifici per questo modello se si voleva.

1

Ecco cosa ho fatto.L'esempio mostra solo il gestore di inserto generico.

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; 

Ora, io solo devo creare manubrio modelli, senza alcun significativo JavaScript codifica per gestire gli eventi generici e legare in su come segue.

$(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()); 

Ora, non devo scrivere alcun modello di mappe di eventi per gestire il CRUD di base. Posso creare un numero qualsiasi di modelli di manubri purché la/route corrisponda al nome della collezione. Anche se di tanto in tanto faccio alcune conversioni difficili. Fondamentalmente, il gestore di eventi generici collega gli eventi, in base alla route aka request.controller, a una raccolta e lo riassume attraverso un modello di dati condivisi client/server per la convalida e persino il controllo di accesso accanto a ciò che esiste in Meteor.

Sembra funzionare bene e ha ridotto significativamente il mio codice base. Ho dozzine di raccolte in cui non ho dovuto scrivere alcun gestore di mappe di eventi perché il CRUD di base è gestito ma abbastanza astratto da poter personalizzare convalide, sicurezza e altri controlli di integrità sul modello di dati condivisi client/server.

0

L'approccio che ho seguito a questo problema in Meteor 1.0.2 è quello di utilizzare modelli dinamici. Vedi Dan Dascalescu's canonical answer e docs.

Supponiamo di avere un insieme di eventi generici collegati al modello "A" e di sfruttarli nei modelli "B", "C" e "D."

HTML:

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

JS:

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

si definisce una funzione di supporto per "A" che raccoglie in modo dinamico, che di B, C, o D (...) che si desidera comprendono:

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'; 
    } 
})  

Gli eventi definiti in "a" sarà ora disponibile in "B", "C" e "D"

Si noti che il modello "A" non deve contenere alcun tipo di HTML.

Problemi correlati