2012-12-09 94 views
42

我遇到了一個模板上下文情況,我很難找到解決辦法。在流星模板和模板助手中訪問父上下文


這裏是有問題的模板:

{{#each votes}} 
    <h3>{{question}}</h3> 

    <ul> 
     {{#each participants}} 
      <li> 
       <p>{{email}}</p> 
       <select name="option-select"> 
        {{#each ../options}} 
        <option value="{{option}}" class="{{is_selected_option}}">{{option}}</option> 
        {{/each}} 
       </select> 
      </li> 
     {{/each}} 
    </ul> 
</div> 
{{/each}} 


而這裏的投票文檔的例子:

{ 
    _id: '32093ufsdj90j234', 
    question: 'What is the best food of all time?' 
    options: [ 
     'Pizza', 
     'Tacos', 
     'Salad', 
     'Thai' 
    ], 
    participants: [ 
     { 
      id: '2f537a74-3ce0-47b3-80fc-97a4189b2c15' 
      vote: 0 
     }, 
     { 
      id: '8bffafa7-8736-4c4b-968e-82900b82c266' 
      vote: 1 
     } 
    ] 
} 


而這裏的問題.. 。

當模板下降到參與者的#each時,它不再能夠訪問vote上下文,因此無法訪問每個投票的可用選項。

我可以有些解決這個問題,通過使用../options車把路徑跳回到父上下文,但這並不影響模板輔助的情況下,所以在thisTemplate.vote.is_selected_option指當前participant,不到當前的voteoption,並且無法知道我們當前正在迭代哪個option

有關如何解決此問題的任何建議,而不訴諸DOM操作和jQuery shenanigans?

這是一個模板問題,多次出現在我身上。我們需要一種在模板,模板助手和模板事件中達成模板上下文層次結構的正式方法。

回答

4

這不是特別漂亮,但我做了這樣的事情:

<template name='forLoop'> 
{{#each augmentedParticipants}} 
{{> participant }} 
{{/each}} 
</template> 

<template name='participant'> 
... 
Question: {{this.parent.question}} 
... 
</template> 


// and in the js: 
Template.forLoop.helpers({ 
    augmentedParticipants: function() { 
     var self = this; 
     return _.map(self.participants,function(p) { 
      p.parent = self; 
      return p; 
     }); 
    } 
}); 

它類似於AVGP提出的辦法,但在輔助級別而不是分貝水平,增強了數據,我認爲是有點輕。

如果你喜歡,你可以嘗試編寫一個Handlebars幫助程序eachWithParent來抽象這個功能。流星的擴展車把這裏記載:https://github.com/meteor/meteor/wiki/Handlebars

+0

zorlak:我最終做的和你的例子非常相似:創建了一個擴大的'participants_with_vote_info'集合,包含了我需要的所有東西,並用'#each'遍歷它,這樣我就不需要跳回到家長。感謝您的想法! – cmal

+3

很好的答案 - 但這很糟糕。這應該被修復 – Chet

+0

對於一個深嵌套的模板佈局這是一個相當痛苦的屁股 –

2

我不知道正式的方式(如果有的話),但要解決您的問題,我想通過這樣的父ID鏈接參與者:

{ 
    _id: "1234", 
    question: "Whats up?", 
    ... 
    participants: [ 
     { 
     _id: "abcd", 
     parent_id: "1234", 
     vote: 0 
     } 
    ] 
} 

,並使用此PARENT_ID在助手,事件等使用findOne跳回到父項。 這顯然是一個次優的事情,但這是最簡單的方式,只要沒有辦法引用父上下文,就會想到這一點。 也許有一種方法,但它很好地隱藏在流星的內部工作中,如果是這樣的話,在文檔中沒有提及:請更新這個問題,如果你找到一個。

+0

你是對的,這將是次優的,但它會工作。一個類似的選擇是使用一個單獨的用戶集合,每個用戶存儲他們的相關投票ID。如果有其他人有其他方法,請告訴我。 – cmal

+0

我應該補充一點,這些解決方案都不會解決_biggest_問題,即{{#each ../ options}}中的每個Template.votes.option都不知道它實際引用了哪個選項! – cmal

2

這是一個長鏡頭,但也許這可以工作:

{{#with ../}} 
    {{#each options}} 
    {{this}} 
    {{/each}} 
{{/with}} 
2

這應該使生活更輕鬆。

// use #eachWithParent instead of #each and the parent._id will be passed into the context as parent. 
Handlebars.registerHelper('eachWithParent', function(context, options) { 

    var self = this; 
    var contextWithParent = _.map(context,function(p) { 
     p.parent = self._id; 
     return p; 
    }); 

    var ret = ""; 

    for(var i=0, j=contextWithParent.length; i<j; i++) { 
     ret = ret + options.fn(contextWithParent[i]); 
    } 
    return ret; 
}); 

繼續前進,改變

p.parent = self._id; 

任何你想要在父上下文訪問。

固定它:

// https://github.com/meteor/handlebars.js/blob/master/lib/handlebars/base.js 

// use #eachWithParent instead of #each and the parent._id will be passed into the context as parent. 
Handlebars.registerHelper('eachWithParent', function(context, options) { 
    var self = this; 
    var contextWithParent = _.map(context,function(p) { 
     p.parent = self._id; 
     return p; 
    }); 

    return Handlebars._default_helpers.each(contextWithParent, options); 
}); 

這工作:)沒有錯誤

+0

我得到這個錯誤'異常來自Deps afterFlush函數:錯誤:無法在同一分支中創建第二個地標'當我嘗試改變某些東西與每個母狗一起呈現 – Chet

82

似乎因爲Spacebars (Meteor's new template engine),你必須使用內../{{#each}}塊訪問父上下文。

在Meteor 0.9.1中,您也可以編寫一個幫手,並在其實現中使用Template.parentData()

+8

這是Meteor 0.8的正確答案。 – JJJ

+3

@opyh,你會添加一個對[Template.parentData(numLevels)](http://docs.meteor.com/#template_parentdata)的引用嗎?我認爲這會進一步改善這個答案。 –

+4

所以你會做''這工作對我來說。 (Meteor 1.0+) – Michael

2

只需註冊一個全局模板幫手:

Template.registerHelper('parentData', 
    function() { 
     return Template.parentData(1); 
    } 
); 

,並用它在你的HTML模板爲:

{{#each someRecords}} 
    {{parentData.someValue}} 
{{/each}} 

=======編輯

流星1.2+ ,您推薦使用:

UI.registerHelper('parentData', function() { 
    return Template.parentData(1); 
}); 
+1

但你的例子中的「someRecords」是什麼?當然這必須來自parentData上下文 - 但是當您嘗試訪問#each子句中的parentData時,您的解決方案似乎不起作用 –

0

我被困在一個類似的方式,發現其他答案中建議的Template.parentData()方法目前在事件處理程序中不起作用(請參閱https://github.com/meteor/meteor/issues/5491)。用戶Lirbank發表在這個簡單的解決方法:

從外上下文中的數據傳遞給一個html元素在內部上下文中,在相同的模板:

{{#each companies}} 
    {{#each employees}} 
    <a href="" companyId="{{../id}}">Do something</a> 
    {{/each}} 
{{/each}} 

現在公司ID可以從事件處理程序被訪問喜歡的東西

$(event.currentTarget).attr('companyId') 
0

"click .selected":function(e){ 
 
    var parent_id = $(e.currentTarget).parent().attr("uid"); 
 
    return parent_id 
 
    },
<td id="" class="staff_docs" uid="{{_id}}"> 
 
             {{#each all_req_doc}} 
 
               <div class="icheckbox selected "></div> 
 
    {{/each}} 
 
    </td>

0

{{#each parent}}

{{#each child}}

<input type="hidden" name="child_id" value="{{_id}}" />

<input type="hidden" name="parent_id" value="{{../_id}}" />

{{/each}}

{{/each}}

的_id沒有的東西_did,我t是父母的ID!

相關問題