Mike Depies
Mike Depies

Reputation: 815

Template #each & rendering

Why does the template get rendered the number of times that correlates with the Each in my template.

<template name="carousel">
<div class="pikachoose">
<ul class="carousel" >
{{#each article}}
    <li><a href="#"><img src="{{image}}" width="500" height="250"  alt="picture"/></a><span>{{caption}}</span></li>
{{/each}}
   </ul>
   </div>

</template>

Template.carousel.article = function () {
return News.find({},{limit: 3});

}

Template.carousel.rendered = function() {
//$(".pika-stage").remove();
alert($(".carousel").html());
//$(".carousel").PikaChoose({animationFinished: updateNewsPreview});
}

In this case it would alert 3 times.

Upvotes: 0

Views: 119

Answers (2)

Hubert OG
Hubert OG

Reputation: 19544

That's the way Meteor handles data updates. Your article data function returns a cursor that is to be used in the template. Initially, the cursor is empty, and data is pulled from the server, one article at a time. Each time an article is fetched, the contents of cursor are changed (it now has one more article), and therefore the reactive article method causes template to rerender.

 


 

If you need to be sure that your code runs only once, there are several possibilities depending on what you need.

The easiest one is just to use created instead of rendered.

If you modify DOM elements, you can also mark elements you modify so that you won't process them twice:

Template.carousel.rendered = function() {
    _.each(this.findAll('.class'), function(element){
        if($(element).data('modified')) return;
        $(element).data('modified', true);
        ...
    });
};

You can disable reactivity for the cursor, though it's a sad solution:

Articles.find(..., {reactive: false});

The most invasive, but also the most versatile is to observe when the data is fully loaded:

Deps.autorun(function() {
    Meteor.subscribe('articles', {
        ready: function() {
            ...
        },
    });
});

Upvotes: 1

Daniel Bernhard
Daniel Bernhard

Reputation: 382

The issue may have to do with the use of the .rendered callback. Each time the loop runs the DOM is updated so the callback will run again.

When I had this problem in the past, I found it helpful to use Meteor event handlers whenever possible, to eliminate load order issues like this one. In this case, maybe you could try a timeout, so that that the .remove() and .PikaChoose() calls only run after the DOM has been quiet for a certain interval. Hope that works for you.

Upvotes: 0

Related Questions