流星:模板呈现数据后的调用函数 [英] Meteor: Call function after template is rendered with data

查看:70
本文介绍了流星:模板呈现数据后的调用函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在轮播中显示许多帖子.对于轮播,我使用 OwlCarousel .

I have a number of posts that I want to display inside of a carousel. For the carousel, I use 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-部分完成之前或在数据到达之前,将调用Template.featuredCarousel.rendered内部的函数.

The result I get is that Owl basically thinks that I just have one item to display in the carousel which are multiple divs. 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.

如何使实例化轮播的函数仅在完全渲染包含所有数据的模板后才能调用?

How can I make the function instantiating the carousel only be called after the template is fully rendered including all data?

非常感谢您的帮助.

P.S .:我使用Iron-Router进行路由,如下所示:

P.S.: I use iron-router for routing like so:

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

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

P.P.S.: I have also tried using a loading template but that doesn't help either.

推荐答案

您已通过以下方式正确识别了问题:

You have identified your problem correctly by stating that :

显然发生的是,在模板的#each-部分完成之前或在数据到达之前,将调用Template.featuredCarousel.rendered内部的函数.

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.

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

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.

您可以做的是在触发rendered回调之前确保数据已准备就绪. 显然,您尝试过设置此解决方案没有任何运气,确定要添加默认的加载钩子吗?

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

我不熟悉owl-carousel,所以我不确定reinit是否可以正常工作(我已经快速检查了文档,但是看起来还可以).

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).

对于无法使用reinit方法的类似JS插件(例如,引导轮播),您可以首先检查该插件是否已实例化,然后销毁并重新创建,如下所示:

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

这篇关于流星:模板呈现数据后的调用函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆