Meteor 模板更新不一致
Inconsistent updating of Meteor template
将 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 刷新,我最初没有注意到发生了正确的行为。
为了完整起见,您可能还应该共享方法代码(即 'projects.add-count'
和 'projects.delete-count'
)。
话虽这么说,我怀疑他们更新文档的 counts
数组字段 _id
等于 Projects
集合中的 projectId
。
在这种情况下,查看您的 'project-counts'
出版物,我们发现它依赖于 Projects.findOne
查询,该查询在服务器端对标准 Meteor 没有反应。
因此,当您添加 "count" 时,会发生一个新文档被添加到 Counts
集合中,并且它的 _id
很可能正确地记录在项目的 counts
字段,但这不会重新执行您的发布代码。因此,游标选择器查询未更改,您的客户端在其 Counts
集合中未收到任何修改。
假设您的方法代码同时加载到客户端和服务器中,客户端执行存根/模拟,插入这个新文档并在本地更新项目的 counts
,触发 UI 更新。
但是随后您的服务器也执行了该方法,这导致发布没有变化,因此 Counts
中的新文档不会发送到客户端,客户端将其隐藏起来。这会产生您观察到的闪烁。
现在,当您从 Counts
中 删除 文档时,我们可以假设您特别将其从 Counts
集合中删除,然后更新发布游标,这就是为什么您的 UI 正确反映了删除,即使发布查询选择器没有更改。
最后,当您 刷新 页面时,您的发布代码将完全重新评估,使用 Projects
集合中的最新版本的文档,这会导致一个正确的查询选择器,因此您的新光标现在包括 Counts
.
中新添加的文档
那么要解决你的问题,你应该尝试使用反应式连接或发布复合包。
例如参见 (Meteor.publish: publish collection which depends on other collection)
将 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 刷新,我最初没有注意到发生了正确的行为。
为了完整起见,您可能还应该共享方法代码(即 'projects.add-count'
和 'projects.delete-count'
)。
话虽这么说,我怀疑他们更新文档的 counts
数组字段 _id
等于 Projects
集合中的 projectId
。
在这种情况下,查看您的 'project-counts'
出版物,我们发现它依赖于 Projects.findOne
查询,该查询在服务器端对标准 Meteor 没有反应。
因此,当您添加 "count" 时,会发生一个新文档被添加到 Counts
集合中,并且它的 _id
很可能正确地记录在项目的 counts
字段,但这不会重新执行您的发布代码。因此,游标选择器查询未更改,您的客户端在其 Counts
集合中未收到任何修改。
假设您的方法代码同时加载到客户端和服务器中,客户端执行存根/模拟,插入这个新文档并在本地更新项目的 counts
,触发 UI 更新。
但是随后您的服务器也执行了该方法,这导致发布没有变化,因此 Counts
中的新文档不会发送到客户端,客户端将其隐藏起来。这会产生您观察到的闪烁。
现在,当您从 Counts
中 删除 文档时,我们可以假设您特别将其从 Counts
集合中删除,然后更新发布游标,这就是为什么您的 UI 正确反映了删除,即使发布查询选择器没有更改。
最后,当您 刷新 页面时,您的发布代码将完全重新评估,使用 Projects
集合中的最新版本的文档,这会导致一个正确的查询选择器,因此您的新光标现在包括 Counts
.
那么要解决你的问题,你应该尝试使用反应式连接或发布复合包。
例如参见 (Meteor.publish: publish collection which depends on other collection)