2016-10-24 18 views
1

Meteor(Blaze)の反応依存ツリーで作業していますが、これを実行する最良の方法が見つかりませんでした。Meteor:オブジェクト属性の親子依存テンプレートを取得する

まず、私は属性elements(配列)を持つitemオブジェクトを、設定した容器を持っている。この例では問題

elements属性はループであり、そのインスタンスごとに子テンプレートがロードされます。

要素は子テンプレートで更新できますが、更新はコンテナに伝播されません。

さらに、からitem ReactiveVarを更新するためにAddボタンを追加しました。 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) 
    } 
}) 

プレビュー

流星が埋め込みコードに統合できないため、いくつかの画像を作成します。

デフォルトページ

enter image description here

更新入力は、コンテナが再すべてのコンテナをレンダリングし、新しい値

を取得する、新しいアイテムを追加します。

enter image description here

をレンダリングに影響しませんでした

解決策1?は、私が子供に全体ReactiveVarを送信することは、子供に.set()メソッドを使用するための解決策になることができるよりも知っている子

item ReactiveVarを送信します。

しかし、私はこのハックを使用している場合、私は(最高ではない)各elementFormに全体itemを送信する必要があります

Exemple

/* 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

実際には良い質問です。私は主にあなたのソリューションの種類を行う場合に応じ

私見1.

何かのように:あなたは#eachでそれに反復する場合次に

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

、あなただけの現在の要素を注入しますあなたの子供の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) {} 

私はそれをテストしていないが、私はあなたのアイデアを与える:

また、イベントの2番目のパラメータとしてテンプレートインスタンスに直接アクセスすることができます。

希望すると、これが役立ちます。

+0

あなたは 'ReactiveVar'を持っていなくても、' container'の 'item'を更新しますか?子テンプレートに作成しますか? – Arthur

+0

なぜアイテムをreactVarにラップしますか?あなたが更新したい唯一のものは要素のデータです。ですから、ある意味では、あなたの親にReactVarによって各子供の価値に応じた時間を持たせることになります。 –

+0

ハム大丈夫!私はすべての要素が現在ReactiveVarである部分を見逃していました。うまくいきましたが、 'item'オブジェクト(私の場合はmongodbオブジェクトで' meteor-astronomy'パッケージを使用しています)は子供のtempalteに対して行われた更新についての情報を持っていません。私は、リアクティブオブジェクト(そして単一のvarだけではない)の場合、強烈な親子テンプレートのコールバックを使用すると思います。 – Arthur

関連する問題