2012-01-11 70 views
5

我使用Ember,Ember Data和Handlebars來顯示具有多種不同類型模型的時間線。我目前的實施雖然運作良好,但似乎可以通過一項公約和一個幫手來大幅改進。但是,我無法弄清楚如何使用已定義的模板。使用Ember +把手在運行時動態選擇視圖

這是我有:

{{#view App.AccountSelectedView contentBinding="App.selectedAccountController.everythingSorted"}} 
    {{#with content}} 
    <ol class="timeline"> 
     {{#each this}} 
     {{#is constructor="App.Design"}} 
     ... stuff about the design 
     {{/is}} 
     {{#is constructor="App.Order"}} 
     ... stuff about the order 
     {{/is}} 
     {{#is constructor="App.Message"}} 
     ... stuff about the message 
     {{/is}} 
     {{/each}} 
    </ol> 
    {{/with}} 
{{/view}} 

...與助手一起...

Handlebars.registerHelper('is', function(options) { 
    if (this.constructor == options.hash["constructor"]) { 
    return options.fn(this); 
    } 
}); 

我寧願依靠一些約定,以找出查看渲染。例如:

<script type="text/x-handlebars-template" data-model="App.Design" id="design-view"> 
... stuff about the design 
</script> 

<script type="text/x-handlebars-template" data-model="App.Order" id="order-view"> 
... stuff about the order 
</script> 

也許數據模型屬性可以用來確定如何呈現對象。

{{#view App.SelectedAccountView contentBinding="App.selectedAccountController.everythingSorted"}} 
    {{#with content}} 
    <ol class="timeline"> 
     {{#each this}} 
     {{viewish this}} 
     {{/each}} 
    </ol> 
    {{/with}} 
{{/view}} 

唉,我想不出如何從助手訪問模板。

Handlebars.registerHelper('viewish', function(options) { 
    // Were I able to access the templates this question 
    // would be unnecessary. 
    // Handlebars.TEMPLATES is undefined... 
}); 

另外,這是我應該用手把做的事嗎?

回答

1

這只是我的頭頂:我會爲每個模型類型創建一個單獨的模板/視圖。例如。會有DesignViewOrderView,等等。每個部分都會指定與TEMPLATENAME(所有代碼的CoffeeScript)使用模板:

App.DesignView = Em.View.extend 
    templateName: 'design' 

App.OrderView = Em.View.extend 
    templateName: 'order' 

所有的自定義繪製每種類型的將視圖/模板內部完成。

在這一點上,我們需要有一些模板邏輯來決定爲每個項目顯示哪個視圖。 最簡單的要做的事情就是將viewType存儲在模型上。

App.Design = Em.Model.extend 
    viewType: App.DesignView 

App.Order = Em.Model.extend 
    viewType: App.OrderView 

然後模板可能看起來像:

{{#collection contentBinding="App.selectedAccountController.everythingSorted"}} 
    {{view content.viewType contentBinding="content"}} 
{{/collection}} 

這不是理想的,但是,因爲我們不希望模型瞭解視圖層。相反,我們可以創建一些工廠邏輯來爲模型創建視圖。然後,我們可以創建一個包含模型的陣列和它們對應的視圖控制器上的計算性能:

App.selectedAccountController = Em.ArrayController.create 
    .. 
    viewForModel: (model) -> 
    # if model is instance of Design return DesignView, Order return OrderView etc. 
    everythingSortedWithViews: (-> 
    everythingSorted.map (model) -> 
     {model: model, viewType: @viewForModel(model)} 
).property('everythingSorted') 

模板會再看看這樣的:

{{#collection contentBinding="App.selectedAccountController.everythingSortedWithView"}} 
    {{view content.viewType contentBinding="content.model"}} 
{{/collection}} 

有對可能更好的方法做這個。我很樂意聽到更接近Ember核心的人提供解決方案。

4

我解決了這個用混入建立我自己的約定。模型對應於具有相似名稱的視圖。例如,一個應用程序。設計模型實例對應於視圖App.DesignView。

App.ViewTypeConvention = Ember.Mixin.create({ 
    viewType: function() { 
    return Em.getPath(this.get('constructor') + 'View'); 
    }.property().cacheable() 
}); 

我這個混合到我的模型......

App.Design.reopen(App.ViewTypeConvention); 
App.Order.reopen(App.ViewTypeConvention); 

...和迭代混合收集這樣的:

{{#each content}} 
    {{view item.viewType tagName="li" contentBinding="this"}} 
{{/each}} 

這樣,我避免定義公約明確地在我的模型中。感謝Gordon,我意識到視圖可以通過在對象上使用屬性來指定。我仍然很想聽到解決這個問題的「正確」方法。

1

這是我用於類似場景的東西。

模型'頁面'hasMany'活動'。

// App.PageModel 
export default DS.Model.extend({ 
    index  : DS.attr('number'), 
    activity : DS.hasMany('activity', { async: true }) 
}); 

模型'活動'具有屬性'類型',它引用哪個模板用於另一個屬性'配置'中的內容。

// App.ActivityModel 
export default DS.Model.extend({ 
    activityId : DS.attr('string'), 
    type   : DS.attr('string'), 
    page   : DS.belongsTo('page', { async: true }), 
    configuration : DS.attr() 
}); 

請注意缺少配置的屬性類型。這提供了存儲隨機結構化對象集合的方法。對於一致結構化的對象,我建議使用Ember-Data.Model-Fragments

主要模板:

{{! page.hbs }} 
{{#with activity}} 
    {{#each}} 
     {{partial type}} 
    {{/each}} 
{{/with}} 

對於類型: '靜態',它使用{{{3鬍子選項}}}渲染HTML字符串。

{{! static.hbs }} 
{{{configuration.content}}} 

其他選項要複雜得多,但仍然使用'with'進行簡化。即:類型:「選擇題」,

{{! multiplechoice.hbs }} 
{{#with configuration}} 
    {{#each options}} 
    <label {{bind-attr class=":label selected:checked:unchecked"}}> 
     {{view Ember.Checkbox checkedBinding="selected" }} 
     {{#if text.content}} 
      {{{text.content}}} 
     {{else}} 
      {{text}} 
     {{/if}} 
    </label> 
    {{/each}} 
    {{ ...etc... }} 
{{/with}} 

利用諧音,記得要考慮根據您的環境命名和/或文件夾結構,即「_partialname.hbs」或「視圖名/ partialname.hbs」