You have identified your problem correctly by stating that :
What apparently happens is that the function inside Template.featuredCarousel.rendered is called before the #each-part of the template is completed or before the data has arrived.
The rendered
callback of a Template is only called once when your template instance is first inserted in the DOM, so if your data is not ready (fetched from server) yet the #each block won't generate any HTML elements and when you instantiate your carousel it will appear empty.
What you can do is make sure your data is ready before your rendered
callback fires.
Apparently you've tried to setup this solution with no luck, are you sure you added the default loading hook like so ?
Router.onBeforeAction("loading");
An even better solution is to listen for database changes in your rendered callback and reinitialize your carousel accordingly when items are first fetched, and then dynamically added and/or removed.
HTML
<template name="carousel">
<div class="owl-carousel">
{{#each featuredPosts}}
{{! item declaration}}
{{/each}}
</div>
</template>
JS
function featuredPosts(){
return Featured.find();
}
Template.carousel.helpers({
// feed the #each with our cursor
featuredPosts:featuredPosts
});
Template.carousel.rendered=function(){
var options={...};
// first initialization
this.$(".owl-carousel").owlCarousel(options);
this.autorun(_.bind(function(){
// this is how we "listen" for databases change : we setup a reactive computation
// and inside we reference a cursor (query) from the database and register
// dependencies on it by calling cursor.forEach, so whenever the documents found
// by the cursor are modified on the server, the computation is rerun with
// updated content, note that we use the SAME CURSOR that we fed our #each with
var posts=featuredPosts();
// forEach registers dependencies on the cursor content exactly like #each does
posts.forEach(function(post){...});
// finally we need to reinit the carousel so it take into account our newly added
// HTML elements as carousel items, but we can only do that AFTER the #each block
// has finished inserting in the DOM, this is why we have to use Deps.afterFlush
// the #each block itself setup another computation and Deps.afterFlush makes sure
// this computation is done before executing our callback
Tracker.afterFlush(_.bind(function(){
this.$(".owl-carousel").data("owlCarousel").reinit(options);
},this));
},this));
};
I'm not familiar with owl-carousel so I'm not sure if reinit will act properly (I've quickly checked the documentation and is seems OK though).
For similar JS plugins where a reinit method is not available (bootstrap carousel for example), you can first check if the plugin has been instantiated then destroy it and recreate it like this :
var carousel=this.$(".carousel").data("bs.carousel");
if(carousel){
// bootstrap carousel has no destroy either so we simulate it by pausing it
// and resetting the data attribute to null (it's a bit messy)
this.$(".carousel").carousel("pause");
this.$(".carousel").data("bs.carousel",null);
}
// initialize normally because previous instance was killed
this.$(".carousel").carousel({...});