Meteor:等到呈现所有模板

时间:2014-09-10 13:10:28

标签: javascript meteor

我有以下模板代码

<template name="home">
    <div class="mainBox">
        <ul class="itemList">
            {{#each this}}
                {{> listItem}}
            {{/each}}
        </ul>
    </div>
</template>

<template name="listItem">
    <li class="item">
        {{username}}
    </li>
</template>

我想在呈现所有“listItem”后执行代码。大约有100个。我尝试了以下

Template.home.rendered = function() {
   // is this called once all of its 'subviews' are rendered?
};

但它不会等到所有视图都被加载。

知道何时加载所有子视图模板的最佳方法是什么?

5 个答案:

答案 0 :(得分:3)

这就是我的工作方式:

client/views/home/home.html

<template name="home">
  {{#if itemsReady}}
    {{> itemsList}}
  {{/if}}
</template>

<template name="itemsList">
  <ul>
    {{#each items}}
      {{> item}}
    {{/each}}
  </ul>
</template>

<template name="item">
  <li>{{value}}</li>
</template>

client/views/home/home.js

Template.home.helpers({
  itemsReady:function(){
    return Meteor.subscribe("items").ready();
  }
});

Template.itemsList.helpers({
  items:function(){
    return Items.find();
  }
});

Template.itemsList.rendered=function(){
  // will output 100, once
  console.log(this.$("li").length);
};

lib/collections/items.js

Items=new Mongo.Collection("items");

server/collections/items.js

insertItems=function(){
  var range=_.range(100);
  _.each(range,function(index){
    Items.insert({value:"Item "+index});
  });
};

Meteor.publish("items",function(){
  return Items.find();
});

server/startup.js

Meteor.startup(function(){
  Items.remove({});
  if(Items.find().count()===0){
    insertItems();
  }
});

我们指定只在发布准备好时才呈现项目列表,因此到那时数据可用,并且正确数量的li元素将显示在列表呈现的回调中。

现在使用iron:router waitOn功能相同:

client/views/home/controller.js

HomeController=RouteController.extend({
  template:"home",
  waitOn:function(){
    return Meteor.subscribe("items");
  }
});

client/lib/router.js

Router.configure({
  loadingTemplate:"loading"
});

Router.onBeforeAction("loading");

Router.map(function(){
  this.route("home",{
    path:"/",
    controller:"HomeController"
  });
});

client/views/loading/loading.html

<template name="loading">
  <p>LOADING...</p>
</template>

使用iron:router可能更好,因为它优雅地解决了一个常见模式:我们不再需要itemsReady助手,只有当waitOn返回的WaitList全局时才会呈现主模板准备好了。

不要忘记添加加载模板并设置默认的“加载”钩子,否则它将无效。

答案 1 :(得分:1)

我遇到了同样的问题,需要等待我的所有子模板加载才能调用一个灵活的JavaScript carousel插件(或任何很酷的JavaScript插件,如图表或图形,需要在调用它之前加载DOM中的整个数据集)。

我通过简单地将子模板的等级与应该为我正在进行的任何查询返回的总计数进行比较来解决它。一旦排名等于计数,您就可以从subtemplate.rendered帮助程序调用您的插件,因为所有子模板都已插入到DOM中。所以在你的例子中:

Template.listItem.rendered = function() {

    if(this.data.rank === ListItems.find({/* whatever query */}).count()) {
       console.log("Last item has been inserted into DOM!");
       //  Call your plugin
       $("#carousel").owlCarousel({
          //  plugin options, etc.
       });
    }
}

然后你只需要listItems的帮助者返回排名,这很容易:

Template.home.helpers({

    listItems: function() {         
        return ListItems.find({/* whatever query */}).map(function(listItem, index) {
           listItem.rank = index + 1;  //  Starts at 1 versus 0, just a preference
        });
    }
}

答案 2 :(得分:0)

以这种方式呈现的方法

当Template.myTemplate的实例呈现到DOM节点并首次放入文档时,将调用此回调。

因此,在渲染时,在这种情况下你没有变量反应。

// this would sufficient
Template.listItem.helpers = function() {
   username:function(){
      return ...
   }
};

答案 3 :(得分:0)

我建议像:

var unrendered = [];

Template.listItem.created = function () {
  var newId = Random.id();
  this._id = newId;
  unrendered.push(newId);
};

Template.listItem.rendered = function () {
  unrendered = _.without(unrendered, this._id);
  if (!unrendered.length) {
    // WHATEVER NEEDS DOING WHEN THEY'VE ALL RENDERED
  }
};

<强> CAVEAT

这假设基本上所有模板实例都会在第一个模板实例呈现之前创建,否则您的代码将在它应该之前运行。我认为应该是这种情况,但你必须尝试一下,因为我没有时间进行100+子模板测试。如果这种情况,那么我不知道如何在不事先知道将创建多少个子模板的情况下如何实现这种行为。

如果知道会有多少,那么上面的代码可以简化为每次rendered运行时减少的计数器,并且很容易。

unrendered = [number of listitems];

Template.listItem.rendered = function () {
  unrendered--;
  if (!unrendered) {
    // WHATEVER NEEDS DOING WHEN THEY'VE ALL RENDERED
  }
};

此外,您可能需要meteor add random,但我认为此软件包现已包含在核心中。

答案 4 :(得分:0)

显然,有各种方法可以处理您的情况。您可以轻松使用模板订阅。

Template.myView.onCreated(function() {
    var self = this;

    self.autorun(function(){
        self.mySub = self.subscribe('mySubscription');
    });

    if(self.mySub.ready()) {
        // my sweet fancy code...
    }
});


<template name="myTemplate">
    <ul>
        {{#if Template.subscriptionsReady}}
           {{#each items}}
               <li>{{item}}</li>
           {{/each}}
        {{else}}
          <div class="loading">Loading...</div>
        {{/if}}
    </ul>
</template>