2012-08-02 14 views
6

Quiero crear un controlador genérico de eventos que pueda reutilizar en elementos dom para que no tenga que escribir la placa de la caldera una y otra vez. Pensé que lo había resuelto, pero estoy recibiendo errores.En Meteor, ¿cómo puedo crear un controlador de eventos genérico?

El problema que tengo es que creo que los controladores de eventos están vinculados en un momento diferente al que necesito. Tal vez en document.ready? Donde creo que necesito adjuntarlos con el método .live()? Aunque no tengo idea de lo que estoy hablando aquí.

Aquí es lo que estoy tratando de hacer:

aplicación de varias páginas.

Colecciones múltiples donde se deben insertar datos.

Código de botón para mostrar el formulario de inserción.

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

que muestra el formulario basado en la página (controlador)

{{> groups_insert}} 

Aquí es 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> 

Aquí está el código del cliente para implementar el botón que muestra el formulario en la página.

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

Aquí es mi genérico controlador de eventos

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; 

EL ERROR

Uncaught TypeError: Cannot call method 'btn_events' of undefined 

PERO, si defino el controlador de eventos de esta manera y lo llaman de esta manera es que funciona .

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

El problema yo no quiero tener que replicar código por todo el sitio con el fin de implementar un buen botón que puede slideToggle y la forma en cualquier página. Si pudiera abstraerlo, debería poder tener un tipo de botón Mostrar formulario en todas las páginas para cualquier colección que esté procesando y que permita la entrada de datos. Además, esto permite crear un manejador de formulario para todas las formas y luego vincularlas al controlador a través de una acción para el modelo.

¿Alguna idea?

Respuesta

10

Puede enlazar una plantilla de alto nivel con elementos creados con plantillas secundarias. Entonces solo tienes que hacer el enlace una vez. Por ejemplo

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

Así que si al final de la creación de 10 definiciones de plantillas diferentes bajo la configuración de lo que aún es suficiente con obligar al controlador a una sola plantilla.

+1

Esto funciona genial. Estoy desaprobando mi código anterior. Creo que en algún momento del pasado esto no funcionó con una versión anterior de Meteor. Mi solución original tenía más de un año. –

3

Siento que estás complicando demasiado las cosas. ¿Por qué no hacer esto?

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

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

Esto tiene el equilibrio adecuado de la separación: el controlador de eventos se define una vez, pero se puede decir cada plantilla que desea sus botones para escuchar a algún evento. Y si eso no es lo suficientemente bueno, puede favorecerlo abstracta:

Template.someTemplate.events(genericEvents); 

y posiblemente incluso combinar genericEvents con eventos específicos para esa plantilla si querías.

1

Esto es lo que terminé haciendo.El ejemplo solo muestra el controlador genérico de inserción.

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; 

Ahora, me basta con crear plantillas manillares sin ninguna codificación significativa Javascript para manejar eventos genéricos y conectarlos de la siguiente manera.

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

Ahora, no tengo que escribir ningún mapa de eventos de plantilla para manejar CRUD básico. Puedo crear cualquier cantidad de plantillas de manillar siempre que la ruta/corresponda con el nombre de la colección. Aunque hago algunas conversiones difíciles de vez en cuando. Básicamente, el controlador genérico de eventos conecta los eventos, basados ​​en la ruta aka request.controller, a una colección y los abstrae a través de un modelo de datos compartidos cliente/servidor para validación e incluso control de acceso junto con lo que existe en Meteor.

Parece que funciona bien y ha reducido significativamente mi código base. Tengo docenas de colecciones en las que no he tenido que escribir ningún manejador de mapas de eventos porque se maneja CRUD básico, pero se abstraen lo suficiente como para poder personalizar validación, seguridad y otras verificaciones de cordura en el modelo de datos compartidos cliente/servidor.

0

El enfoque que he tomado para este problema en Meteor 1.0.2 es usar plantillas dinámicas. Ver Dan Dascalescu's canonical answer y docs.

Digamos que tiene un conjunto de eventos genéricos adjuntos a la plantilla "A" y desea aprovecharlos en las plantillas "B", "C" y "D".

HTML:

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

JS:

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

se define una función auxiliar para "A" que recoge dinámicamente cuál de B, C, o D (...) que desea incluir:

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

Los acontecimientos definidos en "a" será ahora disponible en "B", "C" y "D"

Tenga en cuenta que la plantilla "A" no debe contener ningún tipo de HTML.

Cuestiones relacionadas