[SOLVED] MeteorJS can't use countDown in each

#1

Hello everyone,
Above all, I thank the people who will take the time to answer this subject and help me see it more clearly.

I’m French, I’m sorry if my English is far from perfect.

To start, I develop a web application under meteorJS, and I have a problem with a small system that is simple enough. I want to create a countdown system. For that I use the plugin https://hilios.github.io/jQuery.countdown/.

My html page looks like this:

<template name="horaire">
    <div class="body">
        <div class="grid">
            <table class="horaire-arret">
                <tbody>
                <tr>
                    <th>Ligne {{countDown}}</th>
                    <th>Destination</th>
                    <th>Départ dans</th>
                </tr>
                {{#each depart }}
                <tr>
                    <td><img src="/images/picto/{{numero_vehicule}}.jpg" alt="ligne"></td>
                    <td>{{nom_destination}}</td>
                    <td data-countdown="2019/01/01"></td>
                </tr>
                {{/each}}
                <tr class="annuler">
                    <td><img src="/images/picto/11.jpg" alt="picto"></td>
                    <td>ANVERS <img src="/images/picto/picto-trafic.png" alt="info-trafic"></td>
                    <td>06 min</td>
                </tr>
                </tbody>
            </table>
            <div class="infos-trafic">
                <div class="head-trafic">
                    <h1><img src="/images/picto/picto-trafic-jaune.png" alt="Alerte">INFOS TRAFIC<img src="/images/picto/picto-trafic-jaune.png" alt="Alerte"></h1>
                </div>
                <div class="body-trafic">
                    <p><img src="/images/picto/11.jpg" alt="11"> En raison de fortes manifestations, un retard de 5 minutes est à prévoir.</p>
                    <p><img src="/images/picto/20.jpg" alt="20"> En raison de fortes manifestations, un retard de 5 minutes est à prévoir.</p>
                    <p><img src="/images/picto/11.jpg" alt="11"> En raison de fortes manifestations, un retard de 5 minutes est à prévoir.</p>
                    <p><img src="/images/picto/11.jpg" alt="11"> En raison de fortes manifestations, un retard de 5 minutes est à prévoir.</p>
                    <p><img src="/images/picto/11.jpg" alt="11"> En raison de fortes manifestations, un retard de 5 minutes est à prévoir.</p>
                </div>
            </div>
        </div>
        <div class="pub">
            <p>PUBLICITE FORMAT 1830 (970) X 250px</p>
        </div>
</div>
</template>

and my js page to this:

import './horaire.html';

Meteor.subscribe('depart');

Template.horaire.helpers({
    depart: () => {
        return Depart.find();
    }
});

Template.horaire.onRendered(() => {
    $('[data-countdown]').each(function() {
        let $this = $(this), finalDate = $(this).data('countdown');
        $this.countdown(finalDate, function(event) {
            $this.html(event.strftime('%M min));
        });
    });
});

The problem is the following:
My code in horaire.js starts before my code which is in the loop {{#each}} of the horaire.html file is completely loaded, result nothing is displayed between the tags <td data-countdown="2019/01/01"></td> !

Here is the structure of my meteorJs application:

  • client

– compatibility

– lib

– stylesheets

  • imports

– api

– modules

– startup

— both

— client

— server

– ui

— components

— layouts

— less

— pages

  • private

  • public

  • server

my files horaire.js and horaire.html are in : imports/ui/pages/

How to solve this problem?

Thanks

#2

I typically wrap section of my template in a subscriptions ready to ensure I don’t paint stuff to the glass untill have the data to do so.

Check out - https://themeteorchef.com/tutorials/loading-patterns

Not sure if this will solve your issue but I have run into scenarios in the past where I am trying to do stuff to the dom before the target element is even painted etc.

1 Like
#3

The issue you have is due to your {{#each...}}. That part of the template is reactive - it will not exist initially - even in the onRendered function. The usual way to resolve this is to put that section in its own template as follows:

Replace

  {{#each depart }}
  <tr>
    <td><img src="/images/picto/{{numero_vehicule}}.jpg" alt="ligne"></td>
    <td>{{nom_destination}}</td>
    <td data-countdown="2019/01/01"></td>
  </tr>
  {{/each}}

with (as @drollins suggested):

{{#if Template.subscriptionsReady}}
  {{> departs}}
{{/if}}

Then, add a new template:

<template name="departs">
  {{#each depart }}
  <tr>
    <td><img src="/images/picto/{{numero_vehicule}}.jpg" alt="ligne"></td>
    <td>{{nom_destination}}</td>
    <td data-countdown="2019/01/01"></td>
  </tr>
  {{/each}}
</template>

next, remove Meteor.subscribe('departs'); and put your subscription in the horaire.onCreated:

Template.horaire.onCreated(() => {
  this.subscribe('depart');
});

Finally, change your template’s horaire onRendered and helpers from horaire to departs:

Template.departs.onRendered(() => {
  $('[data-countdown]').each(function () {
    let $this = $(this), finalDate = $(this).data('countdown');
    $this.countdown(finalDate, function (event) {
      $this.html(event.strftime('%M min'));
        });
  });
});

Template.departs.helpers({
  depart() => {
    return Depart.find();
  }
});

Also, you’re missing a closing quote in this line: $this.html(event.strftime('%M min));

1 Like
#4

Hello,

thank you both so much for your help.

I made the changes well, however I encounter this error:
Exception from Tracker recompute function:
meteor.js:992:11
TypeError: _this.subscribe is not a function

I don’t understand why.

my publishing code is in: imports/startup/server/depart.js
and its code:

Meteor.publish('depart', function(){
    return Depart.find({}, {fields: {'nom_arret':1, 'nom_destination':1, 'numero_vehicule':1}});
});

My file imports/ui/pages/horaire.js :

import '../../ui/components/departs.js';
import './horaire.html';

Template.horaire.onCreated(() => {
    this.subscribe('depart');
});

Template.departs.onRendered(() => {
    $('[data-countdown]').each(function () {
        let $this = $(this), finalDate = $(this).data('countdown');
        $this.countdown(finalDate, function (event) {
            $this.html(event.strftime('%M min'));
        });
    });
});

Template.departs.helpers({
    depart: () => {
    return Depart.find().fetch();
}
});

My file imports/ui/pages/horaire.html

<template name="horaire">
    <div class="body">
        <div class="grid">
            <table class="horaire-arret">
                <tbody>
                <tr>
                    <th>Ligne</th>
                    <th>Destination</th>
                    <th>Départ dans</th>
                </tr>
                {{#if Template.subscriptionsReady}}
                    {{> departs}}
                {{/if}}
                <tr class="annuler">
                    <td><img src="/images/picto/11.jpg" alt="picto"></td>
                    <td>ANVERS <img src="/images/picto/picto-trafic.png" alt="info-trafic"></td>
                    <td>06 min</td>
                </tr>
                </tbody>
            </table>
            <div class="infos-trafic">
                <div class="head-trafic">
                    <h1><img src="/images/picto/picto-trafic-jaune.png" alt="Alerte">INFOS TRAFIC<img src="/images/picto/picto-trafic-jaune.png" alt="Alerte"></h1>
                </div>
                <div class="body-trafic">
                    <p><img src="/images/picto/11.jpg" alt="11"> En raison de fortes manifestations, un retard de 5 minutes est à prévoir.</p>
                    <p><img src="/images/picto/20.jpg" alt="20"> En raison de fortes manifestations, un retard de 5 minutes est à prévoir.</p>
                    <p><img src="/images/picto/11.jpg" alt="11"> En raison de fortes manifestations, un retard de 5 minutes est à prévoir.</p>
                    <p><img src="/images/picto/11.jpg" alt="11"> En raison de fortes manifestations, un retard de 5 minutes est à prévoir.</p>
                    <p><img src="/images/picto/11.jpg" alt="11"> En raison de fortes manifestations, un retard de 5 minutes est à prévoir.</p>
                </div>
            </div>
        </div>
        <div class="pub">
            <p>PUBLICITE FORMAT 1830 (970) X 250px</p>
        </div>
    </div>
</template>

My file departs.js

import './departs.html';

And my file departs.html

<template name="departs">
    {{#each depart }}
    <tr>
        <td><img src="/images/picto/{{numero_vehicule}}.jpg" alt="ligne"></td>
        <td>{{nom_destination}}</td>
        <td data-countdown="2019/01/01"></td>
    </tr>
    {{/each}}
</template>

Where is wrong ? and what is the difference between this.subscribe and meteor.subscribe?

Also, you’re missing a closing quote in this line: $this.html(event.strftime(’%M min));
No, just a copy/paste error :roll_eyes:

Thank you a lot for ur help ! :heart:

#5

Ok, done !
That was the problem:

Template.horaire.onCreated(() => {
    this.subscribe('departure');
});

which I replaced with :

Template.horaire.onCreated(function() {
    this.subscribe('departure')
});

And everything works!! Thank you so much!:heart:

1 Like
#6

Yes - sorry, I missed that one! Well done :slight_smile:

1 Like