Question

When I try to use this.findAll on a template where the selector is in a sub-template, findAll returns nothing.

Here's the HTML:

<template name="products">
    {{#each productList}}
        {{> product }}
    {{/each}}
</template>
<template name="product">
    <div class="box">{{name}}</div>
</template>

Here's the JS:

Template.products.helpers({
    productList: function() {
        var all = Products.find({}).fetch();
        return all;
    }
});
Template.products.rendered = function(){
    var boxes = this.findAll('.box');
    console.log(boxes.length);
}

Output of boxes.length is 0. Any ideas how I could get the "box" elements?

Was it helpful?

Solution 3

Here's the correct answer. I've added this to my iron-router route:

action : function () {
    if (this.ready()) {
        this.render();
    }
}

Found the answer from https://stackoverflow.com/a/23576039/130237 while I was trying to solve a different problem.

OTHER TIPS

According to the docs for findAll:

Only elements inside the template and its sub-templates can match parts of the selector.

So it should work for sub-templates. I tried this with a fixed array of products and it worked, which implies that you are just seeing a delay between the call to rendered and the products being fetched. For example if you do:

Template.products.events({
  'click .box': function (e, t) {
    var boxes = t.findAll('.box');
    console.log(boxes.length);
  }
});

Then if you click on one of the boxes, you should see the correct number logged to the console. In short, I think the test may just be invalid. If you are using iron-router, you could try adding a waitOn for the products - that may ensure they arrive before the rendered call.

Here's what I did to run a script after all products have been loaded.

I've added last_product property in all the products.

Template.products.helpers({
    productList: function() {
        var all = Products.find({}).fetch();
        var total = all.length;
        var ctr = 0;
        all.forEach(function(doc){
            doc.last_product = false;

            ctr++;
            if(ctr == total)
            {
                doc.last_product = true;
            }
            return doc;
        });
        return all;
    }
});

Then instead of "Template.products", I used "Template.product" to detect if the last product is rendered. When the last product is rendered, run the script.

Template.product.rendered = function(){
    if(this.data.last_product){
        var boxes = $('.pbox');
        console.log(boxes.length);
    }
}

boxes.length now has the correct length.

Thanks to David for the idea!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top