javascript - tipos - ¿Cómo ejecutar una devolución de llamada después de que se haya realizado#each?
prompt javascript ejemplo (4)
No hay una manera fácil de recibir notificaciones cuando un bloque de {{#each}}
ha realizado la representación en el DOM de cada elemento que se repite.
La mejor solución es usar otro cálculo reactivo ( Tracker.autorun
) para observar sus datos actuales (reactivos).
Cada vez que se modifican los datos actuales (que probablemente sea un cursor), puede ejecutar código arbitrario después de que se realicen todos los cálculos reactivos realizando su tarea, utilizando Tracker.afterFlush
.
El bloque {{#each}}
es uno de esos cálculos, cuya función es escuchar la fuente de datos reactiva que le da como argumento y rerender su Template.contentBlock
tantas veces como elementos recuperados de la fuente que se itera, con el elemento actual como contexto de datos actual.
Al escuchar exactamente la misma fuente de datos reactiva que el {{#each}}
bloqueador auxiliar y ejecutar el código DESPUÉS de que haya finalizado su propio cálculo reactivo, puede obtener el comportamiento real solicitado sin depender de algunos trucos extraños.
Aquí está la implementación completa de este patrón:
JS
Template.content.helpers({
currentData: function(){
return Template.currentData();
}
});
Template.content.onRendered(function(){
this.autorun(function(){
var cursor = Template.currentData();
// we need to register a dependency on the number of documents returned by the
// cursor to actually make this computation rerun everytime the count is altered
var count = cursor.count();
//
Tracker.afterFlush(function(){
// assert that every items have been rendered
console.log(this.$("[data-cid]") == count);
}.bind(this));
}.bind(this));
});
Tengo problemas con una devolución de llamada después de que #each
ha terminado. Tengo una plantilla llamada "contenido":
<template name="content">
{{#if Template.subscriptionsReady}}
{{#each currentData}}
<div data-cid="{{this._id}}"></div>
{{/each}}
{{else}}
Loading...
{{/if}}
</template>
Al principio, espero una suscripción, cuando esté disponible, repito a través de mi Colección con {{#each}}
y {{#each}}
el div
. Lo que necesito es una especie de devolución de llamada para cuando se complete el bucle for-each (en otras palabras DOM listo).
Template.content.onRendered()
-> desencadena a principios
También intenté anexar una imagen después del {{each}} y encendí una función en su onload
esta manera:
<img style="height:0;width:0" src="*mysource*" onload="callback()">
-> funcionó a veces pero no confiable de alguna manera
¿Hay alguna forma de obtener esta devolución de llamada? No tengo miedo de cambiar la estructura de esta plantilla, si eso trae la solución.
También puede usar submodelos y contar la cantidad de subpáginas que se representan. Si este número es el número de elementos en la colección, entonces todos son renderizados.
<template name="content">
{{#if Template.subscriptionsReady}}
{{#each currentData}}
{{> showData}}
{{/each}}
{{else}}
Loading...
{{/if}}
</template>
<template name="currentData">
<div data-cid="{{this._id}}"></div>
</template>
Con eso, inicializa una variable reactiva y rastrearla:
var renderedCount = new ReactiveVar(0);
Tracker.autorun(function checkIfAllRendered() {
if(renderedCount.get() === currentData.count() && renderedCount.get() !== 0) {
//allDataRendered();
}
});
Cuando se currentData
plantilla de datos currentData
y disminuya cuando se destruya.
Template.currentData.onRendered(function() {
renderedCount.set(++renderedCount.curValue);
});
Template.currentData.onDestroyed(function() {
renderedCount.set(--renderedCount.curValue);
});
Un enfoque posiblemente más simple a considerar: cree una plantilla alrededor de su #each
block y luego obtenga un evento onRendered después:
html:
<template name="content">
{{#if Template.subscriptionsReady}}
{{> eachBlock}}
{{else}}
Loading...
{{/if}}
</template>
<template name="eachBlock">
{{#each currentData}}
<div data-cid="{{this._id}}"></div>
{{/each}}
</template>
js:
Template.eachBlock.onRendered(function(){
console.log("My each block should now be fully rendered!");
});
Tuve un problema similar y después de mucha búsqueda encontré la siguiente solución. Intenté usar Tracker
, onRendered
y otros trucos, ninguno funcionó. Esto podría considerarse más un hack, pero funciona. Desafortunadamente no recuerdo dónde encontré esta solución inicialmente.
Comience con su plantilla, pero agregue una etiqueta de plantilla después de each
.
<template name="content">
{{#if Template.subscriptionsReady}}
{{#each currentData}}
<div data-cid="{{this._id}}"></div>
{{/each}}
{{doneTrigger}}
{{else}}
Loading...
{{/if}}
</template>
Luego defina un helper que devuelva nulo.
Template.content.helpers({
doneTrigger: function() {
Meteor.defer(function() {
// do what you need to do
});
return null;
}
});
Puedes leer más sobre Meteor.defer()
aquí , pero es equivalente a usar un setTimeout
0 milisegundos.