Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to execute a callback after an #each is done?

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.

like image 269
ant45de Avatar asked Sep 08 '15 15:09

ant45de


People also ask

How do you execute a callback?

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.

When callback is executed?

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.

How do you wait for callback function to finish?

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.

How do you handle callback errors?

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.


1 Answers

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));
});
like image 74
saimeunt Avatar answered Sep 25 '22 05:09

saimeunt