Meteor:如何获取Object属性

时间:2016-10-24 20:17:38

标签: javascript templates meteor meteor-blaze

我正在使用Meteor上的反应依赖树(使用Blaze),但我找不到最佳方法。

首先,问题

在这个例子中,我有容器设置了一个item对象,它有一个属性elements(数组)。

elements属性是循环,并为每个实例加载子模板。

元素可以在子模板上更新,但更新不会传播到容器。

另外,我添加了Add按钮来更新item ReactiveVar(来自container)。在容器上更新item后,每个字段呈现都会更新,因此对象已更新但未重新呈现。

HTML

<template name="container">
  {{#let item=getItem}}
    <h1>Update {{item._id}}</h1>
    {{#each element in item.elements}}
      <div>
        {{> elementForm element}}
        <small>{{element.name}}</small>
      </div>
    {{/each}}
  {{/let}}
  <button name="add">Add</button>
</template>


<template name="elementForm">
  {{#let el=getEl}}
    <input value="{{el.name}}"/>
  {{/let}}
</template>

父模板

Template.container.onCreated(function onContainerCreated() {
  // From data
  let item = {
    _id: '123abc',
    elements: [
      {name: "El #1"},
      {name: "El #2"},
      {name: "El #3"},
    ]
  }
  // Create master ReactiveVar
  this.item = new ReactiveVar(item);
});

Template.container.helpers({
  getItem() {
    return Template.instance().item.get();
  },
});
Template.container.events({
  // Add a new element (Will refresh all elements render)
  'click button[name="add"]'(e) {
    let instance = Template.instance()
    let item = instance.item.get()
    item.elements.push({name: "new El"})
    instance.item.set(item)
  },
})

儿童模板

/* Element */
Template.elementForm.onCreated(function onElementCreated() {
  this.el = new ReactiveVar(this.data)
});
Template.elementForm.helpers({
  getEl() {
    return Template.instance().el.get()
  }
})
Template.elementForm.events({
  'change input'(e) {
    let instance = Template.instance()
    let el = instance.el.get()
    el.name = e.currentTarget.value
    instance.el.set(el)
  }
})

预览

由于meteor无法集成在Embed代码上,我会制作一些图像。

默认页面

enter image description here

更新输入不影响容器渲染

enter image description here

添加新项目,将重新渲染所有容器并获取新值

enter image description here

解决方案1?向孩子发送item ReactiveVar

我知道,将整个ReactiveVar发送给孩子可以是对孩子使用.set()方法的解决方案。

但如果我使用此hack,我必须将整个item发送给每个elementForm(不是最好的)

为例

/* Html */
<Template name="parentTemplate">
  <small>{{getFoo}}</small>
  {{> childTemplate getItem}}
</Template>
<Template name="childTemplate">
  <input value="{{getFoo}}" />
</Template>

/* Parent */
Template.parentTemplate.onCreated(function onParentCreated() {
  this.item = new ReactiveVar({ foo: bar})
});
Template.parentTemplate.helpers({
  getFoo() {
    return Template.instance().item.get().foo    
  },
  getItem() {
    return Template.instance().item // Send reactive var, net value (.get)
  }
})
/* Child */
Template.childTemplate.onCreated(function onChildCreated() {
  this.item = this.data.item // Use Parent Reactive var
});
Template.childTemplate.helpers({
  getFoo() {
    return Template.instance().item.get().foo    
  },
})
 Template.childTemplate.events({
  'change input'(e) {
    let item = Template.instance().item.get()   
    item.foo = e.currentTarget.value
    Template.instance().item.set(item) // Will update parent   
  },
})

解决方案2?回调

另一个解决方案是除了元素数据之外,还向子模板发送每个操作的回调(如更改),以通知父模板更新特定元素的主ReactiveVar。

示例

/* Html */
<Template name="parentTemplate">
  <small>{{getFoo}}</small>
  {{> childTemplate getData}}
</Template>
<Template name="childTemplate">
  <input value="{{getFoo}}" />
</Template>

/* Parent */
Template.parentTemplate.onCreated(function onParentCreated() {
  this.item = new ReactiveVar({ foo: bar})
});
Template.parentTemplate.helpers({
  getFoo() {
    return Template.instance().item.get().foo    
  },
  getData() {
    let instance = Template.instance()
    return {
      item: instance.item.get(),
      onChange: function(val) {
        // Update item here
        let item = instance.item.get()
        item.foo = val
        instance.item.set(item)
      }
    }
  }
})
/* Child */
Template.childTemplate.onCreated(function onChildCreated() {
});
Template.childTemplate.helpers({
  getFoo() {
    return Template.instance().data.item.foo    
  },
})
 Template.childTemplate.events({
  'change input'(e) {
    // Call parent callback
    Template.instance().data.onChange(e.currentTarget.value)  
  },
})

最终问题

处理父/子模板以处理项目对象中的元素列表的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

其实是个好问题。

恕我直言,视情况而定,我大部分都是你的解决方案1。

类似的东西:

Template.container.onCreated(function(){
  //each elements are ReactiveVar
  let item = {
    _id: '123abc',
    elements: [
      {name: new ReactiveVar("El #1")},
      {name: new ReactiveVar("El #2")},
      {name: new ReactiveVar("El #3")},
    ]
  }
  // I don't wrap the wole item on a ReactiveVar if I don't need it.
});

然后,当您使用#each进行迭代时,您只会将当前元素数据注入您孩子的datacontext。从这里,你可以很容易地做到:

Template.childTemplate.helpers({
  getName() {
    return this.name.get();    
  },
})
 Template.childTemplate.events({
  'change input'(e, tp) {
    newVal = e.currentTarget.value
    tp.currentData().name.set(newVal); 
  }
});

我使用了一些“快捷方式”作为Template.currentData(),并使用this.name.get()在帮助程序上直接访问datacontext。

您还可以直接访问模板实例作为事件的第二个参数:

'change input'(event, templateInstance) {}

我没有测试它,我只是给你这个想法。

希望这会对你有所帮助。