我正在学习Meteor JS中的Session和被动数据源。它们非常适合设置全局UI状态。但是,我无法弄清楚如何将它们范围限定为模板的特定实例。
以下是我正在尝试做的事情
我在页面上有多个满足的元素。每个下面都是一个“编辑”按钮。当用户单击“编辑”按钮时,它应该关注元素并显示“保存”和“取消”按钮。
如果用户点击“取消”,则会消除所有更改,并且模板实例应使用原始内容重新呈现。
这是我到目前为止的代码
// Helper
Template.form.helpers({
editState: function() {
return Session.get("editState");
}
});
// Rendered
Template.form.rendered = function(e){
var $this = $(this.firstNode);
var formField = this.find('.form-field');
if (Session.get("editState")) formField.focus();
};
// Event map
Template.form.events({
'click .edit-btn' : function (e, template) {
e.preventDefault();
Session.set("editState", "is-editing");
},
'click .cancel-btn' : function (e, template) {
e.preventDefault();
Session.set("editState", null);
},
});
// Template
<template name="form">
<div class="{{editState}}">
<p class="form-field" contenteditable>
{{descriptionText}}
</p>
</div>
<a href="#" class="edit-btn">Edit</a>
<a href="#" class="save-btn">Save</a>
<a href="#" class="cancel-btn">Cancel</a>
</template>
// CSS
.edit-btn
.cancel-btn,
.save-btn {
display: inline-block;
}
.cancel-btn,
.save-btn {
display: none;
}
.is-editing .cancel-btn,
.is-editing .save-btn {
display: inline-block;
}
问题
如果我有Form
个模板的多个实例,那么.form-field
会针对每个模板进行关注,而不仅仅是正在编辑的模板。我如何制作,只有被编辑的人才会聚焦?
答案 0 :(得分:2)
您可以使用data
呈现模板,该模板基本上只是插入页面时传递给它的对象。
数据可能只是Session
editState
中使用的关键。
例如,使用Template.form({editStateKey:'editState-topForm'})
你可以制作一个把手帮手,例如,
Handlebars.registerHelper('formWithOptions',
function(editStateKey){
return Template.form({editStateKey:editStateKey})
});
然后使用
将其插入模板中 {{{formWithOptions 'editState-topForm'}}}
(请注意三联{
,}
)
接下来,将引用从Session.x('editState')
更改为Session.x(this.editStateKey)
/ Session.x(this.data.editStateKey)
Template.form.helpers({
editState: function() {
return Session.get(this.editStateKey);
}
});
// Rendered
Template.form.rendered = function(e){
var $this = $(this.firstNode);
var formField = this.find('.form-field');
if (Session.get(this.data.editStateKey)) formField.focus();
};
// Event map
Template.form.events({
'click .edit-btn' : function (e, template) {
e.preventDefault();
Session.set(this.editStateKey, "is-editing");
},
'click .cancel-btn' : function (e, template) {
e.preventDefault();
Session.set(this.editStateKey, null);
},
});
注意:如果您使用的是iron-router
,则还有其他API可以将data
传递给模板。
注2:在meteor 1.0中,应该有更好的支持来编写自己的小部件。这应该可以更好地控制这类事情。
答案 1 :(得分:1)
作为一项政策问题,我几乎在所有情况下都避免使用Session。我觉得,随着应用程序的增长,他们的全球范围会导致不良习惯和缺乏关于问题分离的良好纪律。另外,由于它们的全局范围,Session在渲染模板的多个实例时会导致麻烦。出于这些原因,我觉得其他方法更具可扩展性。
替代方法
您可以直接执行所需的操作,而不是设置状态然后在其他地方对其做出反应。这里的类根据需要显示和隐藏块:
'click .js-edit-action': function(event, t) {
var $this = $(event.currentTarget),
container = $this.parents('.phenom-comment');
// open and focus
container.addClass('editing');
container.find('textarea').focus();
},
'click .js-confirm-delete-action': function(event, t) {
CardComments.remove(this._id);
},
if (Meteor.isClient) {
Template.hello.created = function () {
// counter starts at 0
this.counter = new ReactiveVar(0);
};
Template.hello.helpers({
counter: function () {
return Template.instance().counter.get();
}
});
Template.hello.events({
'click button': function (event, template) {
// increment the counter when button is clicked
template.counter.set(template.counter.get() + 1);
}
});
}
http://meteorcapture.com/a-look-at-local-template-state/
获取
Router.route('/posts/:_id', {name: 'post'});
PostController = RouteController.extend({
action: function () {
// set the reactive state variable "postId" with a value
// of the id from our url
this.state.set('postId', this.params._id);
this.render();
}
});
集
Template.Post.helpers({
postId: function () {
var controller = Iron.controller();
// reactively return the value of postId
return controller.state.get('postId');
}
});
https://github.com/iron-meteor/iron-router/blob/devel/Guide.md#setting-reactive-state-variables
另一种方法是通过更新集合中的数据来简单说明。有时这很有道理。
在我看来,会话通常是更糟糕的选择。此外,我个人并不使用#3,因为我觉得与铁路的关系更少 - 路由器更好,因为我们想要切换到另一个路由器包,例如“Flow”。