Meteor:模板用数据渲染后的调用函数

时间:2014-08-17 22:02:52

标签: templates meteor iron-router meteor-blaze owl-carousel

我想在旋转木马内显示一些帖子。对于轮播,我使用 OwlCarousel

    <div class="owl-carousel" id="featured-carousel">
        {{#each featuredPosts}}
        <div>
            <h2>
                {{postTitle}}
            </h2>
        </div>
        {{/each}}
    </div>

我这样打电话给我的旋转木马:

Template.featuredCarousel.rendered = function(){
$('#featured-carousel').owlCarousel({
    loop:true,
    autoplay:true,
    autoplayTimeout:3000,
    items:1,
    smartSpeed:1080,
    padding:80
});
this.rendered = true;
};

我得到的结果是猫头鹰基本上认为我只有一个项目要在转盘中显示多个div。显然,在模板的#each-part完成之前或数据到达之前,都会调用Template.featuredCarousel.rendered中的函数。

如何在完全呈现模板(包括所有数据)后才能调用实例化轮播的函数?

非常感谢你的帮助。

P.S。:我像这样使用铁路由器进行路由:

Router.map(function(){
this.route('home', {
    path: '/',
    waitOn: function(){
        return Meteor.subscribe('featured');
    },
    data: function(){
        return {featuredPosts: Featured.find({})};
    }
});
});

P.P.S。:我也尝试过使用加载模板,但这也无济于事。

2 个答案:

答案 0 :(得分:6)

您已通过声明:

正确识别了您的问题
  

显然,在模板的#each-part完成之前或数据到达之前,都会调用Template.featuredCarousel.rendered中的函数。

模板的rendered回调仅在您的模板实例首次插入DOM时调用一次,因此如果您的数据尚未就绪(从服务器获取),则#each块赢了&t生成任何HTML元素,当您实例化轮播时,它将显示为空。

您可以做的是确保在rendered回拨触发之前您的数据已准备就绪。 显然你已经试图设置这个解决方案没有运气,你确定你添加了这样的默认加载钩子吗?

Router.onBeforeAction("loading");

更好的解决方案是在渲染的回调中监听数据库更改,并在首次提取项目时相应地重新初始化您的轮播,然后动态添加和/或删除。

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));
};

我不熟悉猫头鹰旋转木马,所以我不确定reinit是否会正常行动(我已经快速检查了文档,但看起来还不错)。

对于没有reinit方法的类似JS插件(例如bootstrap carousel),你可以先检查插件是否已经实例化然后销毁它并重新创建它:

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({...});

答案 1 :(得分:0)

我们更好地在#each结束而不是onRender之后从模板中调用辅助处理程序。

一旦循环结束并且DOM加载相同,处理程序就会调用该函数。

与您的情况类似,每次将处理程序放置为{{initializeCarousel}}

{{#each featuredPosts}} {{! item declaration}} {{/each}} {{initializeCarousel}}

现在在帮助器中将其定义为:

Template.carousel.helpers({ // feed the #each with our cursor
    initializeCarousel: function(){
        $('#featured-carousel').owlCarousel({
            loop:true, autoplay:true, autoplayTimeout:3000, items:1, smartSpeed:1080, padding:80 
        });
    });

这将使数据加载后加载轮播。希望这会有所帮助。