react - meteor tutorial
Acceder al contexto principal en plantillas de Meteor y ayudantes de plantilla (9)
Es una posibilidad remota, pero tal vez esto podría funcionar:
{{#with ../}}
{{#each options}}
{{this}}
{{/each}}
{{/with}}
Me encuentro con una situación de contexto de plantilla que me cuesta mucho encontrar un camino.
Aquí está la plantilla en cuestión:
{{#each votes}}
<h3>{{question}}</h3>
<ul>
{{#each participants}}
<li>
<p>{{email}}</p>
<select name="option-select">
{{#each ../options}}
<option value="{{option}}" class="{{is_selected_option}}">{{option}}</option>
{{/each}}
</select>
</li>
{{/each}}
</ul>
</div>
{{/each}}
Y aquí hay un ejemplo de un documento de votación:
{
_id: ''32093ufsdj90j234'',
question: ''What is the best food of all time?''
options: [
''Pizza'',
''Tacos'',
''Salad'',
''Thai''
],
participants: [
{
id: ''2f537a74-3ce0-47b3-80fc-97a4189b2c15''
vote: 0
},
{
id: ''8bffafa7-8736-4c4b-968e-82900b82c266''
vote: 1
}
]
}
Y aquí está el problema ...
Cuando la plantilla cae en el #each
para los participantes, ya no tiene acceso al contexto del vote
y, por lo tanto, no tiene acceso a las opciones disponibles para cada voto.
De alguna manera, puedo evitar esto utilizando la ruta de acceso de ../options
para volver al contexto principal, pero esto no afecta el contexto del helper de plantilla, por lo que this
en Template.vote.is_selected_option
refiere al participant
actual, no a la vote
u option
actual, y no tiene forma de saber a qué option
nos referimos actualmente.
¿Alguna sugerencia sobre cómo solucionar esto, sin recurrir a la manipulación DOM y las travesuras jQuery?
Este es un problema de creación de plantillas que me ha surgido muchas veces. Necesitamos una forma formal de alcanzar la jerarquía de contexto de la plantilla, en plantillas, asistentes de plantilla y eventos de plantilla.
Esto debería hacer la vida más fácil.
// use #eachWithParent instead of #each and the parent._id will be passed into the context as parent.
Handlebars.registerHelper(''eachWithParent'', function(context, options) {
var self = this;
var contextWithParent = _.map(context,function(p) {
p.parent = self._id;
return p;
});
var ret = "";
for(var i=0, j=contextWithParent.length; i<j; i++) {
ret = ret + options.fn( contextWithParent[i] );
}
return ret;
});
Adelante y cambia
p.parent = self._id;
a lo que quieras acceder en el contexto principal.
Arreglado:
// https://github.com/meteor/handlebars.js/blob/master/lib/handlebars/base.js
// use #eachWithParent instead of #each and the parent._id will be passed into the context as parent.
Handlebars.registerHelper(''eachWithParent'', function(context, options) {
var self = this;
var contextWithParent = _.map(context,function(p) {
p.parent = self._id;
return p;
});
return Handlebars._default_helpers.each(contextWithParent, options);
});
Esto funciona :) sin error
Me quedé atrapado de una manera similar y descubrí que el enfoque de Template.parentData () sugerido en otras respuestas actualmente no funciona dentro de los manejadores de eventos (ver https://github.com/meteor/meteor/issues/5491 ). El usuario Lirbank publicó esta solución simple:
Pase los datos del contexto externo a un elemento html en el contexto interno, en la misma plantilla:
{{#each companies}}
{{#each employees}}
<a href="" companyId="{{../id}}">Do something</a>
{{/each}}
{{/each}}
Ahora se puede acceder a la identificación de la compañía desde el controlador de eventos con algo como
$(event.currentTarget).attr(''companyId'')
No conozco la forma formal (si es que hay una), pero para resolver su problema, vincularía a los participantes con la ID de los padres de la siguiente manera:
{
_id: "1234",
question: "Whats up?",
...
participants: [
{
_id: "abcd",
parent_id: "1234",
vote: 0
}
]
}
y use este parent_id en helpers, events, etc. para saltar al padre usando findOne. Obviamente, esta es una tarea subóptima, pero es la forma más fácil que se me ocurre siempre que no haya forma de hacer referencia al contexto principal. Tal vez hay una manera, pero está muy bien escondida en el funcionamiento interno de Meteor sin mencionar en los documentos, de ser así: actualice esta pregunta si encuentra una.
No es particularmente bonito, pero he hecho algo como esto:
<template name=''forLoop''>
{{#each augmentedParticipants}}
{{> participant }}
{{/each}}
</template>
<template name=''participant''>
...
Question: {{this.parent.question}}
...
</template>
// and in the js:
Template.forLoop.helpers({
augmentedParticipants: function() {
var self = this;
return _.map(self.participants,function(p) {
p.parent = self;
return p;
});
}
});
Es similar al enfoque sugerido por AVGP, pero aumenta los datos en el nivel de ayuda en lugar del nivel de base de datos, que creo que es un poco más ligero.
Si te apetece, podrías intentar escribir un ayudante de bloque de Handlebars eachWithParent
que eachWithParent
esta funcionalidad. Las extensiones de Meteor para los manubrios están documentadas aquí: https://github.com/meteor/meteor/wiki/Handlebars
Parece que desde Spacebars (el nuevo motor de plantillas de Meteor) , tienes acceso al contexto principal dentro de bloques {{#each}}
usando ../
.
En Meteor 0.9.1, también puede escribir un ayudante y usar Template.parentData()
en su implementación.
Simplemente registre un asistente de plantilla global:
Template.registerHelper(''parentData'',
function () {
return Template.parentData(1);
}
);
y utilízalo en tus plantillas HTML como:
{{#each someRecords}}
{{parentData.someValue}}
{{/each}}
======= EDITAR
Para Meteor 1.2+, debes usar:
UI.registerHelper(''parentData'', function() {
return Template.parentData(1);
});
{{#each parent}}
{{#each child}}
<input type="hidden" name="child_id" value="{{_id}}" />
<input type="hidden" name="parent_id" value="{{../_id}}" />
{{/each}}
{{/each}}
¡El _id NO es el _did de la cosa, es la identificación del padre!
"click .selected":function(e){
var parent_id = $(e.currentTarget).parent().attr("uid");
return parent_id
},
<td id="" class="staff_docs" uid="{{_id}}">
{{#each all_req_doc}}
<div class="icheckbox selected "></div>
{{/each}}
</td>