【问题标题】:Meteor Reactive Nested Object Update Parent ObjectMeteor Reactive 嵌套对象更新父对象
【发布时间】:2015-03-13 13:10:27
【问题描述】:

我正在尝试使 javascript 对象具有响应性,以便在更新子对象时,更新原始(父)对象 - 无论是在视图中还是在 javascript 中。

这几乎可以做到,除非“完成?”单击按钮,console.log 输出仅在第一次准确。之后,正确切换任何子项会更新视图,但底层 javascript 不会更新,因为子项的“选定”值不再正确。

此外,我希望能够简化并简单地让父 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

长话短说,我希望给定的数据上下文(来自一个事件)能够成为一个设置器,这样如果我在一个 {{#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);
}
});
}

【问题讨论】:

    标签: javascript meteor


    【解决方案1】:

    切换到(仅限本地)集合似乎使其具有反应性,我确实必须更新根(父)项(使用Template.parentData())。 所以基本上转换为并专门用作收藏作品。有点烦人,看起来有点像黑客,但我想这就是流星的意义所在,模糊了服务器和客户端之间的界限——只需对所有内容使用集合,让内置的流星反应性发挥它的魔力。

    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});
    }
    });
    }
    

    【讨论】:

    • 这个gist 可能很有趣。它是响应式对象的实现——即具有单个依赖项但具有多个键(和子键)的对象,可以自行显式获取或设置。
    • @user728291 - 该链接转到苹果开发者。
    • 我认为解决方案已经计划好,但不确定何时。非常detailed discussion here。同时,我认为您的解决方法是一种合理的方法。
    • 感谢更新链接@user728291 - 所以看来关键是.field() 设置子键并将其传播到顶级对象?
    猜你喜欢
    • 1970-01-01
    • 2020-03-20
    • 1970-01-01
    • 2016-04-14
    • 2015-08-05
    • 1970-01-01
    • 2016-02-20
    • 2021-12-15
    • 2017-06-29
    相关资源
    最近更新 更多