2015-09-08 11 views
6

Ho problemi con una richiamata dopo che lo #each è terminato. Ho un modello denominato "contenuto":Come eseguire una richiamata dopo aver effettuato #each?

<template name="content"> 
{{#if Template.subscriptionsReady}} 
    {{#each currentData}} 
     <div data-cid="{{this._id}}"></div> 
    {{/each}} 
{{else}} 
    Loading... 
{{/if}} 
</template> 

All'inizio mi aspetto un abbonamento, quando questo è disponibile, ho scorrere la mia collezione con {{#each}} e aggiungere i div. Ciò di cui ho bisogno è una sorta di callback per quando viene eseguito il ciclo for-each (in altre parole DOM ready).

Template.content.onRendered() 

-> innesca ai primi

Ho anche provato aggiungendo un'immagine dopo l'{{ogni}} e fuoco una funzione nella sua onload come questo:

<img style="height:0;width:0" src="*mysource*" onload="callback()"> 

-> lavoro fatto a volte ma non affidabile in qualche modo

C'è un modo per ottenere questa richiamata? Non ho paura di cambiare la struttura di questo modello, se questo porta la soluzione.

+0

Non so se questo è un duplicato, ma ha certamente la stessa sensazione di [questa domanda] (https://stackoverflow.com/questions/30140232/meteor-with-iron-router-cant-get -slick-giostra-lavoro). –

risposta

1

Ho avuto un problema simile e dopo molte ricerche ho trovato il seguente solu zione. Ho provato a utilizzare Tracker, onRendered e altri trucchi, nessuno dei quali ha funzionato. Questo potrebbe essere considerato più di un trucco, ma funziona. Purtroppo non ricordo dove ho trovato questa soluzione inizialmente.

Inizia con il modello, ma aggiungi un tag modello dopo il tuo each.

<template name="content"> 
{{#if Template.subscriptionsReady}} 
    {{#each currentData}} 
     <div data-cid="{{this._id}}"></div> 
    {{/each}} 
    {{doneTrigger}} 
{{else}} 
    Loading... 
{{/if}} 
</template> 

Quindi definire un helper che restituisce null.

Template.content.helpers({ 
    doneTrigger: function() { 
    Meteor.defer(function() { 
     // do what you need to do 
    }); 
    return null; 
    } 
}); 

Potete leggere di più su Meteor.defer()here, ma è equivalente all'utilizzo di un millisecondo 0 setTimeout.

+0

Questa è anche una soluzione molto buona e facile, grazie! – ant45de

+0

Sta usando la natura sincrona di "# each". Interessante, ma potrebbe non sopravvivere a ulteriori aggiornamenti di Blaze! –

+0

In effetti, come detto, considererei questo più di un trucco a questo punto. Anche se ha fatto il lavoro. Essere guardato –

3

Non c'è un modo semplice per ricevere una notifica quando un blocco Spacebars {{#each}} ha eseguito il rendering nel DOM ogni elemento che viene ripetuto.

La soluzione migliore è utilizzare un altro calcolo reattivo (Tracker.autorun) per osservare i dati correnti (reattivi).

Ogni volta che i dati correnti (che è probabilmente un cursore) vengono modificati, è possibile eseguire codice arbitrario dopo che tutti gli altri calcoli reattivi vengono eseguiti eseguendo qualunque sia il loro lavoro, utilizzando Tracker.afterFlush.

Il blocco {{#each}} è uno di quei calcoli, il cui ruolo è quello di ascoltare l'origine dei dati reattiva si dà come argomento e nuovamente sottoposti a rendering sue Template.contentBlock tutte le volte che gli elementi recuperati dalla sorgente viene iterata sopra, con la voce corrente come contesto attuale dei dati.

Ascoltando la stessa sorgente di dati reattivi del blocco di blocchi {{#each}} e eseguendo il codice DOPO aver terminato il proprio calcolo reattivo, è possibile ottenere il comportamento richiesto effettivo senza fare affidamento su alcuni strani trucchi.

Ecco la piena attuazione di questo modello:

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)); 
}); 
+0

Mi piace questa soluzione e penso che sia facile da usare, quindi grazie! Ho già deciso di utilizzare i modelli all'interno di {{#each}} perché ho realizzato una richiamata dopo che ogni elemento è già sufficiente per il mio problema. – ant45de

0

È inoltre possibile utilizzare sotto-modelli e contare il numero di sub-modelli resi. Se questo numero è il numero di elementi nella raccolta, quindi tutti sono resi.

<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 questo, inizializzare una variabile reattivo e seguirli:

var renderedCount = new ReactiveVar(0); 

Tracker.autorun(function checkIfAllRendered() { 
    if(renderedCount.get() === currentData.count() && renderedCount.get() !== 0) { 
    //allDataRendered(); 
    } 
}); 

Quando il modello è reso currentData, incrementarlo, e farlo diminuire quando viene distrutta.

Template.currentData.onRendered(function() { 
    renderedCount.set(++renderedCount.curValue); 
}); 

Template.currentData.onDestroyed(function() { 
    renderedCount.set(--renderedCount.curValue); 
}); 
-1

Un approccio forse più semplice da considerare - creare un modello intorno al vostro #each blocco e quindi ottenere un evento onRendered seguito:

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!"); 
});