流星反应嵌套对象更新父对象
Meteor Reactive Nested Object Update Parent Object
我正在尝试使 javascript 对象具有反应性,以便在更新子对象时更新原始(父)对象 - 在视图和 javascript 中.
除了单击 "Done?" 按钮时,这几乎可以做到,console.log 输出仅在第一次时准确。之后,切换任何子项都会正确更新视图,但基础 javascript 不会更新,因为子项的 "selected" 值不再正确。
此外,我希望能够简化并简单地让父 items
对象在任何子项目被切换为选中或未选中时更新。
我来自 AngularJS,这要简单得多 - 如果您传入一个对象,然后更新该对象的 属性,父对象 属性 也会更新,并且自动保持同步。
似乎 this
和数据上下文是 getter 而不是 setter? Template.currentData()
似乎相关,但我无法让它发挥作用:
https://github.com/meteor/meteor/issues/2010
我获取要更新的项目的方法是通过设置和比较索引来手动更新它,以从内部子数据上下文更新主父对象,但这同样不理想,并且随着您获得更多而变得越来越混乱嵌套,因为我需要所有嵌套索引才能回溯到主 items
对象,然后覆盖整个对象以强制更新。
How to Get Parent Data Context in Meteor on an Event
长话短说,我希望给定的数据上下文(来自一个事件)能够是一个 setter 这样如果我在 {{#each }} 中并且恰好在items[1].subitem[2] 然后我就可以做 this.selected =!this.selected
然后这将有效地更新 items[1].subitem[2].selected
(反应性 - 更新 javascript 对象本身和 DOM ).所以稍后我可以检查 items[1].subitem[2].selected
的值并知道它是可靠和准确的。目前我正在根据 selected
布尔值更新 DOM 但父 items
数组不准确。
HTML / 模板:
<template name="items">
{{#each items}}
<div class='item-title'>{{title}}</div>
<div class='{{classes.cont}}'>
{{#each subitem}}
{{> subitems }}
{{/each}}
</div>
{{/each}}
<div class='btn btn-primary btn-block items-done'>Done?</div>
</template>
<template name="subitems">
<div class='flexbox subitems'>
<div class='flex1 pointer'>{{title}}</div>
{{#if selected}}
<div class='fa fa-check-circle'></div>
{{else}}
<div class='fa fa-plus-circle'></div>
{{/if}}
</div>
</template>
Javascript
if (Meteor.isClient) {
var items1 =[
{
title: 'Item 1',
subitem: [
{
title: 'Sub 1.1'
},
{
title: 'Sub 1.2'
},
{
title: 'Sub 1.3'
}
]
},
{
title: 'Item 2',
subitem: [
{
title: 'Sub 2.1'
},
{
title: 'Sub 2.2'
},
{
title: 'Sub 2.3'
}
]
}
];
var ii, jj;
for(ii =0; ii<items1.length; ii++) {
items1[ii].classes ={
cont: 'hidden'
};
items1[ii].index =ii; //Blaze / Spacebars does not yet give access to index? Maybe @index in html but no equivalent in `this` in javascript?
for(jj =0; jj<items1[ii].subitem.length; jj++) {
items1[ii].subitem[jj].selected =false;
items1[ii].subitem[jj].index =jj;
}
}
Template.items.created =function() {
this.items =new ReactiveVar;
this.items.set(items1);
};
Template.items.helpers({
items: function() {
return Template.instance().items.get();
}
});
Template.items.events({
'click .item-title': function(evt, template) {
var items =template.items.get();
if(this.classes.cont ==='visible') {
this.classes.cont ='hidden';
}
else {
this.classes.cont ='visible';
//hide all others
for(ii =0; ii<items.length; ii++) {
if(ii !==this.index) {
items[ii].classes.cont ='hidden';
}
}
}
template.items.set(items);
},
'click .items-done': function(evt, template) {
console.log(template.items.get()); //TESTING
}
});
Template.subitems.created =function() {
this.selected =new ReactiveVar;
this.selected.set(this.data.selected);
};
Template.subitems.helpers({
selected: function() {
return Template.instance().selected.get();
}
});
Template.subitems.events({
'click .subitems': function(evt, template) {
//toggle selected
this.selected =!this.selected;
template.selected.set(this.selected);
}
});
}
切换到(仅限本地)集合似乎使其具有反应性,我确实不得不更新根(父)项(使用 Template.parentData()
)。
所以基本上转换为并专门用作集合作品。有点烦人,看起来有点像 hack,但我想这就是 meteor 的意义所在,它模糊了服务器和客户端之间的界限——只需对所有内容使用集合,让内置的 meteor 反应性发挥其魔力。
https://www.eventedmind.com/feed/meteor-ui-reactivity-in-slow-motion
if (Meteor.isClient) {
var items1 =[
{
title: 'Item 1',
subitem: [
{
title: 'Sub 1.1'
},
{
title: 'Sub 1.2'
},
{
title: 'Sub 1.3'
}
]
},
{
title: 'Item 2',
subitem: [
{
title: 'Sub 2.1'
},
{
title: 'Sub 2.2'
},
{
title: 'Sub 2.3'
}
]
}
];
var ii, jj;
for(ii =0; ii<items1.length; ii++) {
items1[ii].classes ={
cont: 'hidden'
};
items1[ii].index =ii; //Blaze / Spacebars does not yet give access to index? Maybe @index in html but no equivalent in `this` in javascript?
for(jj =0; jj<items1[ii].subitem.length; jj++) {
items1[ii].subitem[jj].selected =false;
items1[ii].subitem[jj].index =jj;
}
}
ItemCollection = new Meteor.Collection(null);
for(ii =0; ii<items1.length; ii++) {
ItemCollection.insert(items1[ii]);
}
Template.items.helpers({
items: function() {
return ItemCollection.find();
}
});
Template.items.events({
'click .item-title': function(evt, template) {
var items =ItemCollection.find().fetch();
if(this.classes.cont ==='visible') {
this.classes.cont ='hidden';
}
else {
this.classes.cont ='visible';
//hide all others
for(ii =0; ii<items.length; ii++) {
if(ii !==this.index) {
//items[ii].classes.cont ='hidden';
ItemCollection.update(items[ii]._id, {$set: {classes: {cont: 'hidden'} } });
}
}
}
//update current item
ItemCollection.update(this._id, {$set: {classes: {cont: this.classes.cont } } });
},
'click .items-done': function(evt, template) {
console.log(ItemCollection.find().fetch()); //TESTING
}
});
Template.subitems.events({
'click .subitems': function(evt, template) {
//toggle selected
this.selected =!this.selected;
var itemId =Template.parentData(1)._id;
var setObj ={};
setObj['subitem.'+this.index+'.selected'] =this.selected;
console.log(itemId+' '+JSON.stringify(setObj)); //TESTING
ItemCollection.update(itemId, { $set: setObj});
}
});
}
我正在尝试使 javascript 对象具有反应性,以便在更新子对象时更新原始(父)对象 - 在视图和 javascript 中.
除了单击 "Done?" 按钮时,这几乎可以做到,console.log 输出仅在第一次时准确。之后,切换任何子项都会正确更新视图,但基础 javascript 不会更新,因为子项的 "selected" 值不再正确。
此外,我希望能够简化并简单地让父 items
对象在任何子项目被切换为选中或未选中时更新。
我来自 AngularJS,这要简单得多 - 如果您传入一个对象,然后更新该对象的 属性,父对象 属性 也会更新,并且自动保持同步。
似乎 this
和数据上下文是 getter 而不是 setter? Template.currentData()
似乎相关,但我无法让它发挥作用:
https://github.com/meteor/meteor/issues/2010
我获取要更新的项目的方法是通过设置和比较索引来手动更新它,以从内部子数据上下文更新主父对象,但这同样不理想,并且随着您获得更多而变得越来越混乱嵌套,因为我需要所有嵌套索引才能回溯到主 items
对象,然后覆盖整个对象以强制更新。
How to Get Parent Data Context in Meteor on an Event
长话短说,我希望给定的数据上下文(来自一个事件)能够是一个 setter 这样如果我在 {{#each }} 中并且恰好在items[1].subitem[2] 然后我就可以做 this.selected =!this.selected
然后这将有效地更新 items[1].subitem[2].selected
(反应性 - 更新 javascript 对象本身和 DOM ).所以稍后我可以检查 items[1].subitem[2].selected
的值并知道它是可靠和准确的。目前我正在根据 selected
布尔值更新 DOM 但父 items
数组不准确。
HTML / 模板:
<template name="items">
{{#each items}}
<div class='item-title'>{{title}}</div>
<div class='{{classes.cont}}'>
{{#each subitem}}
{{> subitems }}
{{/each}}
</div>
{{/each}}
<div class='btn btn-primary btn-block items-done'>Done?</div>
</template>
<template name="subitems">
<div class='flexbox subitems'>
<div class='flex1 pointer'>{{title}}</div>
{{#if selected}}
<div class='fa fa-check-circle'></div>
{{else}}
<div class='fa fa-plus-circle'></div>
{{/if}}
</div>
</template>
Javascript
if (Meteor.isClient) {
var items1 =[
{
title: 'Item 1',
subitem: [
{
title: 'Sub 1.1'
},
{
title: 'Sub 1.2'
},
{
title: 'Sub 1.3'
}
]
},
{
title: 'Item 2',
subitem: [
{
title: 'Sub 2.1'
},
{
title: 'Sub 2.2'
},
{
title: 'Sub 2.3'
}
]
}
];
var ii, jj;
for(ii =0; ii<items1.length; ii++) {
items1[ii].classes ={
cont: 'hidden'
};
items1[ii].index =ii; //Blaze / Spacebars does not yet give access to index? Maybe @index in html but no equivalent in `this` in javascript?
for(jj =0; jj<items1[ii].subitem.length; jj++) {
items1[ii].subitem[jj].selected =false;
items1[ii].subitem[jj].index =jj;
}
}
Template.items.created =function() {
this.items =new ReactiveVar;
this.items.set(items1);
};
Template.items.helpers({
items: function() {
return Template.instance().items.get();
}
});
Template.items.events({
'click .item-title': function(evt, template) {
var items =template.items.get();
if(this.classes.cont ==='visible') {
this.classes.cont ='hidden';
}
else {
this.classes.cont ='visible';
//hide all others
for(ii =0; ii<items.length; ii++) {
if(ii !==this.index) {
items[ii].classes.cont ='hidden';
}
}
}
template.items.set(items);
},
'click .items-done': function(evt, template) {
console.log(template.items.get()); //TESTING
}
});
Template.subitems.created =function() {
this.selected =new ReactiveVar;
this.selected.set(this.data.selected);
};
Template.subitems.helpers({
selected: function() {
return Template.instance().selected.get();
}
});
Template.subitems.events({
'click .subitems': function(evt, template) {
//toggle selected
this.selected =!this.selected;
template.selected.set(this.selected);
}
});
}
切换到(仅限本地)集合似乎使其具有反应性,我确实不得不更新根(父)项(使用 Template.parentData()
)。
所以基本上转换为并专门用作集合作品。有点烦人,看起来有点像 hack,但我想这就是 meteor 的意义所在,它模糊了服务器和客户端之间的界限——只需对所有内容使用集合,让内置的 meteor 反应性发挥其魔力。
https://www.eventedmind.com/feed/meteor-ui-reactivity-in-slow-motion
if (Meteor.isClient) {
var items1 =[
{
title: 'Item 1',
subitem: [
{
title: 'Sub 1.1'
},
{
title: 'Sub 1.2'
},
{
title: 'Sub 1.3'
}
]
},
{
title: 'Item 2',
subitem: [
{
title: 'Sub 2.1'
},
{
title: 'Sub 2.2'
},
{
title: 'Sub 2.3'
}
]
}
];
var ii, jj;
for(ii =0; ii<items1.length; ii++) {
items1[ii].classes ={
cont: 'hidden'
};
items1[ii].index =ii; //Blaze / Spacebars does not yet give access to index? Maybe @index in html but no equivalent in `this` in javascript?
for(jj =0; jj<items1[ii].subitem.length; jj++) {
items1[ii].subitem[jj].selected =false;
items1[ii].subitem[jj].index =jj;
}
}
ItemCollection = new Meteor.Collection(null);
for(ii =0; ii<items1.length; ii++) {
ItemCollection.insert(items1[ii]);
}
Template.items.helpers({
items: function() {
return ItemCollection.find();
}
});
Template.items.events({
'click .item-title': function(evt, template) {
var items =ItemCollection.find().fetch();
if(this.classes.cont ==='visible') {
this.classes.cont ='hidden';
}
else {
this.classes.cont ='visible';
//hide all others
for(ii =0; ii<items.length; ii++) {
if(ii !==this.index) {
//items[ii].classes.cont ='hidden';
ItemCollection.update(items[ii]._id, {$set: {classes: {cont: 'hidden'} } });
}
}
}
//update current item
ItemCollection.update(this._id, {$set: {classes: {cont: this.classes.cont } } });
},
'click .items-done': function(evt, template) {
console.log(ItemCollection.find().fetch()); //TESTING
}
});
Template.subitems.events({
'click .subitems': function(evt, template) {
//toggle selected
this.selected =!this.selected;
var itemId =Template.parentData(1)._id;
var setObj ={};
setObj['subitem.'+this.index+'.selected'] =this.selected;
console.log(itemId+' '+JSON.stringify(setObj)); //TESTING
ItemCollection.update(itemId, { $set: setObj});
}
});
}