Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/meteor/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-apps-script/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
当所有模板项在Meteor中完成渲染时回调?_Meteor_Publish Subscribe - Fatal编程技术网

当所有模板项在Meteor中完成渲染时回调?

当所有模板项在Meteor中完成渲染时回调?,meteor,publish-subscribe,Meteor,Publish Subscribe,我正在获取一组记录并将它们放在模板中,让它们呈现{{{{#each}},我希望在呈现最后一个DOM节点之前显示一个加载图标 我的问题是,我没有找到一种方法来查询状态/对最后一个要更新/重新绘制的DOM节点上呈现的最后一个项发出回调 在我的HTML文件中看起来有点像这样: <template name="stuff"> {{#each items}} <div class="coolView">{{cool_stuff}}</div>

我正在获取一组记录并将它们放在模板中,让它们呈现
{{{{#each}}
,我希望在呈现最后一个DOM节点之前显示一个加载图标

我的问题是,我没有找到一种方法来查询状态/对最后一个要更新/重新绘制的DOM节点上呈现的最后一个项发出回调

在我的HTML文件中看起来有点像这样:

<template name="stuff">
    {{#each items}}
        <div class="coolView">{{cool_stuff}}</div>
    {{/each}}
</template>
会话变量
loading\u stuff
在Handlebar助手中查询,如果
true
,则返回加载类的名称(带有加载程序图标GIF)

我之所以执行笨拙的
Meteor.setTimeout
,是因为
Template.rendered
是在呈现到模板中的每个项目之后调用的。因此,我需要重新确认它仍在加载,但给它一些时间来加载下一个或完成所有渲染,并稍作停顿,直到它将
load\u stuff
设置为
false

如何在所有DOM更新(针对特定模板或整个页面)结束时以正确的Meteor方式可靠地查询/回调

非常感谢

编辑

使用
onReady()
回调的解决方案只能部分起作用:

在渲染开始之前,模板似乎被调用了多次(2-3次),但在数据从模板渲染所依赖的服务器返回之后。这意味着加载数据已“完成”,但DOM仍在呈现。我将使用Meteor.autorun(),看看是否可以在某个地方找到可靠的钩子来正确地执行此操作。与此同时,我想我最初的问题仍然存在:

如何知道整个模板/页面何时完成渲染

最终编辑:


在一天结束时,根据DOM的结构,开发人员需要有一个坚如磐石的DOM,并尽可能地将适当的回调附加到他/她想要检查其状态的元素上。这似乎是一个不需要思考的问题,但对我来说,知道模板的最后一个元素被呈现的唯一方法是在模板的最末端呈现一个具有特殊id的元素,该元素表示呈现的结束,并向其附加一个
.livequery
回调。我希望Meteor将来能为检查这种状态提供更统一的全球支持。

在我的情况下,部分解决方案是:

onComplete()
回调添加到我的
Items
集合的订阅中,这是任何加载过程的正式结束。因此,在
Template.rendered
中不再使用hacky
setTimeout
s,只需在查询数据时(在
Template.stuff.items
中)将
loading_stuff
设置为
true
,然后在订阅函数的
onComplete()
回调中设置为
false

服务器:

Meteor.publish('items', function (some_param) {
    return Items.find({some_field: some_param});
});
客户:

Meteor.subscribe('items', some_param, function onComplete() {
    Session.set('loading_stuff', false);
});


这是一个局部解决方案,因为知道数据何时从服务器到达以及DOM何时完成渲染是两个独立的问题。

有几个选项:

  • 正如您在最后的评论中提到的,您可以创建您的反应式上下文并在那里处理更改
  • 您可以创建一个特殊值,即._id=“END”,并在模板呈现中查找该值
  • 我的最爱:不要使用集合,而是通过
    Meteor.call
    Meteor.methods
    调用对填充模板。您还可以将结果放入被动变量中,以便模板自动重新呈现
  • 您可能已经发现,
    onReady
    事件是在publish方法调用时触发的,而不是在所有数据都已发送时触发的

    下面是上面#3的一个简单示例:

    在客户端:

      Meteor.call('get_complete_email',id, function(err,doc) {
        if (err === undefined) {
          // Note current_compose is reactive
          current_compose.set(new _ComposePresenter(action, doc));
        } else {
          log_error('compose','get complete email ',err);
        }
      }); 
    
    在服务器中:

     Meteor.methods({
       'get_complete_email': function(id) {
         return Emails.findOne({_id:id, user_id:Meteor.userId}, body_message_fields);
       }
     });
    
    在演示者或查看器代码中:(可以消除
    data
    temp变量-它是遗留的,尚未重构)


    显然,您需要以稍微不同的方式连接当前、当前和您自己的对象。

    您可以使用jquery插件来跟踪特定选择器的dom插入:

    $('.my-rendered-element').livequery(function () {
        console.log('I've been added to the DOM');
    });
    
    如果您还需要确保已加载图像,并且所有内容都呈现良好,您可以使用其他一些实用程序,如此插件,并执行以下操作:

    $('.my-rendered-element').livequery(function () {
        $(this).imagesLoaded(function() {
            console.log('My images have been loaded');
        });
    });
    

    这是一种变通方法,可能与Meteor的集成不太好,但我发现这两个家伙在很多情况下都非常有用。

    我发现JQuery的livequery插件在等待模板中的元素写入DOM时不起作用。这是因为插件侦听JQuery方法,如append,但Meteor不使用JQuery。它使用名为
    LiveRange
    的对象写入DOM。我修改了我的livequery JavaScript文件来处理这个问题

    在文件底部附近,有一行调用
    registerPlugin()
    。我将其修改为如下所示:

    $.livequery.registerPlugin([
    {object:$.fn,方法:['append','prepend','after','before','wrap','attr','removeAttr','addClass','removeClass','toggleClass','empty','remove','html']},
    {对象:LiveRange.prototype,方法:['insertBefore','insertAfter']}
    ]);
    
    然后我修改了registerPlugin()方法,使其如下所示:

    registerPlugin:函数(注册){
    对于(变量i=0;iTemplate.compose_to_cc_bcc_subject.prefilled = function(part) {
      if (Current && Current.compose()) { 
        var data = Current.compose();
        if (data == undefined || data[part] == undefined) { return; }
        return data[part]; 
      } else {
        return;
      }
    }  
    
    $('.my-rendered-element').livequery(function () {
        console.log('I've been added to the DOM');
    });
    
    $('.my-rendered-element').livequery(function () {
        $(this).imagesLoaded(function() {
            console.log('My images have been loaded');
        });
    });
    
    <template name="stuff">
       {{#each items}}
         {{> itemTemplate}}
       {{/each}}
    </template>
    
    <template name="itemTemplate">
       <div class="coolView">{{cool_stuff}}</div>
    </template>
    
    items: function() {   
       return Items.find({whatever: whatever}).map(function(item, index) {
          item.rank = index + 1;
          return item;
       });
    }
    
    Template.stuff.rendered = function() { 
      if(this.data.rank === Items.find({whatever: this.data.whatever}).count()) {
         //  Do something cool like initializing a sweet
         //  JS plugin now that ALL your template instances 
         //  are all rendered
         $("#coolplugindiv").coolJSPluginInit();
      }
    }
    
    <template name="stuff">
      {{#each items}}
        <div class="coolView">{{cool_stuff}}</div>
      {{/each}}
      {{> didMyStuffLoad}}
    </template>
    
    Template.didMyStuffLoad.rendered = function () {
      Session.set('loading_stuff', false);
    }