【问题标题】:Inconsistent updating of Meteor templateMeteor 模板更新不一致
【发布时间】:2017-08-27 07:38:30
【问题描述】:

将 Meteor 与 blaze 模板和流路由器一起使用,我发现如果我创建一个新元素,则页面不会更新以显示它,但如果我删除相同的元素,它会立即消失。这是模板代码:

<template name="EditProject">
    ...
    {{#each currentCounts }}
        <div class="count-box">{{> CountDelete }}</div>
    {{/each}}
    ...
    <btn class="btn waves-effect waves-light h-button" id="add-count">Add Count</btn>
    ...
</template>

<template name="CountDelete">
    <div class="card blue-grey lighten-2 count-box">
        <div class="card-content white-text">
            <span class="card-title">
                {{ name }}
            </span>
            {{ notes }}
        </div>
        <div class="card-action">
            <btn class="btn waves-effect waves-light delete-count">
                <i class="mdi mdi-delete"></i>
            </btn>
            <a class="btn waves-effect waves-light" href="/edit_count/{{ _id }}">
                <i class="mdi mdi-pencil"></i>
            </a>
        </div>
    </div>
</template>

currentCounts的来源是这样的:

Template.EditProject.helpers({
    currentCounts: function() {
        var projectId = FlowRouter.getParam('projectId');
        const project = Projects.findOne(projectId);
        var counts = Counts.find({
            _id: { $in: project.counts }
            },
            {
                sort: { sort_order: -1 }
            }
        );
        return counts;
    }
})

如前所述,单击 .delete-count 按钮会删除关联的计数,还会导致 UI 更新以显示它已消失。添加计数(通过单击#add-count)会正确创建计数,但页面不会更新。有一个短暂的闪烁,但仅此而已,刷新页面会导致新的计数出现。有人可以建议发生了什么吗?

编辑:这是订阅,根据评论中的要求:

Template.EditProject.onCreated(function() {
    var self = this;
    self.autorun(function() {
        var projectId = FlowRouter.getParam('projectId');
        self.subscribe('single-project',projectId);
        self.subscribe('project-counts',projectId);
    })
})

进一步编辑:

第一次访问此路由时,页面会按应有的方式呈现,通过{{#each currentCounts}} 显示多个计数的列表。如果我删除其中一个计数,它会立即从屏幕上消失,但如果我添加一个新计数,它直到我刷新页面才会显示。

另一个编辑:

根据请求添加侦听器和服务器发布代码(在 server/main.js 中)。奇怪的是,当再次启动应用程序时,一切都开始正常运行,但在几分钟内,我一直在描述的相同行为再次出现。

Meteor.publish('project-counts', function projectPublication(projectId) {
    let project = Projects.findOne({_id: projectId, knitter: this.userId});
    return Counts.find({_id: { $in: project.counts }});
});
Meteor.publish('single-project', function projectPublication(projectId) {
    return Projects.find({_id: projectId, knitter: this.userId});
});

'click #add-count'(event) {
    //TODO: Check for duplicate count name
    var projectId = FlowRouter.getParam('projectId');
    var countName = $('#new-count').val();
    var countNotes = $('#new-count-notes').val();

    if (!countName) {
        $("#errors-go-here").empty();
        Blaze.renderWithData(Template.EditProjectErrors, {
            errors: ['You must supply a name for the new count.']
        }, $("#errors-go-here")[0])
        $('.modal').modal();
        $('#validation-errors').modal('open');
        return;
    }

Template.EditProject.events({
    ...
    Meteor.call('projects.add-count',projectId,countName,countNotes, function(error) {
            if (error) {
                console.log("Count add error: " + error);
                Materialize.toast('Failed to add count \'' + countName + '\'!', 3000, 'orange darken-4');
                return false;
            } else {
                Materialize.toast('Count \'' + countName + '\' added!', 3000, 'blue-grey');
                $('#new-count').val(null);
                $('#new-count-notes').val(null);
                // Running this makes the missing count show up, but this is clearly not the right way to do it...
                //location.reload(); 
            }
        });
    },
    ...
)}



Template.CountDelete.events({
    'click .delete-count'(event) {
        var self = this;
        var projectId = FlowRouter.getParam('projectId');
        var countId = self._id;
        const count = Counts.findOne(countId);
        const name = count.name;

        Meteor.call('projects.delete-count',projectId,countId, function(error) {
            if (error) {
                console.log("Count add error: " + error);
                Materialize.toast('Failed to delete count \'' + name + '\'!', 3000, 'orange darken-4');
                return false;
            } else {
                Materialize.toast('Count \'' + count.name + '\' deleted!', 3000, 'blue-grey');
            }
        });

    },

})

更多信息:我发现一旦页面被加载,它的行为就会正常。但是,如果重新加载它,它就会开始出现异常。因此,由于代码更改,Meteor 刷新了页面,因此我最初并没有注意到正确的行为。

【问题讨论】:

  • 你在哪里订阅了counts集合,是在editproject模板的路由的onWait函数中还是在模板的onCreated中?
  • 我更新了帖子以显示订阅数量(和项目)的位置。
  • 据我了解,您从项目集合中获取了一条记录,然后您正在使用该项目 ID 在计数集合中搜索,我希望计数集合与您订阅的项目计数相同到。在 Counts 集合中,您是否发现返回具有 _id = project.id 的所有行
  • 你可以试试这个
    hi {{> CountDelete }}
    看看 hi 是否打印了 count 次。只是为了检查 countDelete 模板是否是问题制造者
  • 一个项目可以有多个计数,每个项目中都会存储一个计数 ID 数组。 currentCounts 应该返回属于该项目的所有计数。显然它确实如此,但是 UI 重绘有一些有趣的事情发生。我已经添加到我的解释中。

标签: javascript meteor meteor-blaze flow-router


【解决方案1】:

为了完整起见,您可能还应该共享方法代码(即'projects.add-count''projects.delete-count')。

话虽如此,我怀疑他们在Projects 集合中将_id 更新为等于projectId 的文档的counts 数组字段。

在这种情况下,查看您的 'project-counts' 发布,我们发现它依赖于 Projects.findOne 查询,该查询在服务器端与标准 Meteor 没有反应。

因此,当您添加“计数”时,会发生一个新文档添加到 Counts 集合中,并且它的 _id 很可能正确记录在项目的 counts 字段中,但这不会重新执行您的发布代码。因此游标选择器查询没有改变,并且您的客户端在其Counts 集合中没有收到任何修改。

假设您的方法代码在客户端和服务器中都加载,客户端执行一个存根/模拟,插入这个新文档并在本地更新项目的counts,从而触发 UI 更新。

但是随后您的服务器也执行了该方法,这导致发布没有变化,因此Counts 中的新文档不会发送到客户端,这会将其隐藏起来。这会产生您观察到的闪烁。

现在,当您从Counts删除一个文档时,我们可以假设您将它从Counts 集合中删除,然后更新发布光标,这就是您的 UI 正确反映的原因删除,即使发布查询选择器没有更改。

最后,当您刷新页面时,您的发布代码将完全重新评估,使用 Projects 集合中的最新版本文档,这会导致正确的查询选择器,因此您的新光标现在包括 Counts 中新添加的文档。

那么要解决您的问题,您应该尝试使用响应式连接或发布复合包。

例如见https://stackoverflow.com/a/32920733/5108796 (Meteor.publish: publish collection which depends on other collection)

【讨论】:

  • 感谢您提供非常有用的解释。您对add-countdelete-count 方法的功能确实是正确的,我发现通过添加您链接的包并更新相关订阅来解决问题。
猜你喜欢
  • 1970-01-01
  • 2015-05-13
  • 1970-01-01
  • 2018-08-27
  • 2017-08-20
  • 2016-10-04
  • 1970-01-01
  • 2013-05-08
  • 2014-10-23
相关资源
最近更新 更多