Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent Meteor.js Templates from rendering without data

Could someone please help me to understand Meteors template behavior?

I would like to implement a notification system in my project, similar to Apples Growl. It uses simple jQuery effects to make a message appear, when a record is written to the database. I've simplified the code example, to show the essential problem:

The code:

var Messages = new Meteor.Collection("messages");

if (Meteor.isClient) {
   Template.Notification.Message = function() {
     return Message.findOne({}, {sort: {seq: -1}});
   };

   Template.Notification.rendered = function() {
    $("#livebar").fadeIn(400).delay(1000).fadeOut(400);
   }
}

The template:

<template name="Notification">
<div class="row">
   <div class="span6 alert alert-error" id="livebar" style="display:none;">
        {{Messages.text}}
   </div>
</div>
</template>

If the page is rendered, an empty invisible area gets rendered with the jQuery effect, and afterwards the system loads the reactive datasource (Message) and renders the area again! I've tried to prevent it from rendering twice, but didn't succeed. The error seems to be quite easy to fix, but I'm stuck here. I would appreciate any help!

like image 394
dimkin Avatar asked Nov 09 '12 17:11

dimkin


2 Answers

You could surround the template call {{> Notification}} with an {{#if}} block.

{{#if has_notifications}}
  {{> Notifications}}
{{/if}}

//JS
Template.foo.has_notifications = function() {
  Message.find().count() > 0;
}    

But as the data arrives not in one piece, it could happen, that a template is rendered multiple times. A timeout could help you there...

like image 156
Andreas Avatar answered Nov 14 '22 22:11

Andreas


You need this extra code:

First execute meteor remove autopublish on the terminal inside your project.

Second define what to publish

//On isServer
Meteor.publish('messages', function(){
    return Messages.find();
});

Then subscribe to that data and wait till its ready

//On isClient
subscription_handle = Meteor.subscribe('messages');

Meteor.autorun( function(computation) {
    if( subscription_handle.ready() ) {

        //The data is now ready, start your templates here

        computation.stop(); //Stop autorun
    } 
});

Also, define your collection as var Messages = new Meteor.Collection("messages"); so its a global variable.

A totally different (but easier) approach is to use the waitOn property of the template route in Iron Router, so your template renders after the data is ready.

like image 38
Cristian Garcia Avatar answered Nov 14 '22 23:11

Cristian Garcia