I'm having trouble with a callback after the #each
has finished. I have a template named "content":
<template name="content">
{{#if Template.subscriptionsReady}}
{{#each currentData}}
<div data-cid="{{this._id}}"></div>
{{/each}}
{{else}}
Loading...
{{/if}}
</template>
At first I wait for a subscription, when this is available, I iterate through my Collection with {{#each}}
and append the div
. What I need is a sort of callback for when the for-each loop is done (in other words DOM ready).
Template.content.onRendered()
-> triggers to early
I also tried appending an image after the {{each}} and fire a function in its onload
like this:
<img style="height:0;width:0" src="*mysource*" onload="callback()">
-> did work sometimes but not reliable somehow
Is there a way to get this callback? I do not fear to change the structure of this template, if that brings the solution.
A custom callback function can be created by using the callback keyword as the last parameter. It can then be invoked by calling the callback() function at the end of the function. The typeof operator is optionally used to check if the argument passed is actually a function. console.
A callback function is a function that occurs after some event has occurred. The reference in memory to the callback function is usually passed to another function. This allows the other function to execute the callback when it has completed its duties by using the language-specific syntax for executing a function.
JavaScript provides a setTimeout() method which can work with the callback function and the await keyword to wait for a function to finish. The objective of employing these methods is to execute a piece of code after waiting for a specific time.
If an error-handling callback function has been specified in the application and if the value of the error parameter is NULL, the error parameter is passed to the specified callback function, and the operation that encountered the error condition returns a value of DW_DLV_ERROR.
There's no easy way to get notified when a Spacebars {{#each}}
block has done rendering into the DOM every item getting iterated over.
The best solution is to use another reactive computation (Tracker.autorun
) to observe your (reactive) current data.
Everytime your current data (which is likely a cursor) is modified, you can run arbitrary code after every other reactive computations are done performing whatever their job is, using Tracker.afterFlush
.
The {{#each}}
block is one of those computations, whose role is to listen to the reactive data source you give it as argument and rerender its Template.contentBlock
as many times as items fetched from the source being iterated over, with the current item as current data context.
By listening to the exact same reactive data source as the {{#each}}
block helper and running your code AFTER it has finished its own reactive computation, you can get the actual requested behavior without relying on some weird tricks.
Here is the full implementation of this pattern :
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));
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With