使用Ember + Handlebars在运行时动态选择视图

Jon*_* M. 5 handlebars.js ember.js

我使用Ember,Ember Data和Handlebars来显示包含许多不同类型模型的时间轴.我目前的实现,虽然功能正常,但似乎可以通过约定和帮助器大幅改进.但是,我无法弄清楚如何使用已定义的模板.

这就是我所拥有的:

{{#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}}
Run Code Online (Sandbox Code Playgroud)

......还有帮手......

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

我宁愿依靠一些约定来确定要渲染的视图.例如:

<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>
Run Code Online (Sandbox Code Playgroud)

也许数据模型属性可用于确定对象的呈现方式.

{{#view App.SelectedAccountView contentBinding="App.selectedAccountController.everythingSorted"}}
  {{#with content}}
    <ol class="timeline">
      {{#each this}}
        {{viewish this}}
      {{/each}}
    </ol>
  {{/with}}
{{/view}}
Run Code Online (Sandbox Code Playgroud)

唉,我无法弄清楚如何从帮助器访问模板.

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

另外,这是我应该用Handlebars做的事情吗?

小智 5

使用ViewStates,请参阅以下示例:

http://jsfiddle.net/rsaccon/AD2RY/


ghe*_*ton 1

这就是我的想法:我将为每种模型类型创建一个单独的模板/视图。例如,会有DesignViewOrderView等。其中每一个都将指定与 templateName 一起使用的模板(所有代码均为 CoffeeScript):

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

App.OrderView = Em.View.extend
  templateName: 'order'
Run Code Online (Sandbox Code Playgroud)

每种类型的所有自定义渲染都将在视图/模板内完成。

此时,我们需要一些模板逻辑来决定为每个项目显示哪个视图。最简单的方法是将 viewType 存储在模型上。

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

App.Order = Em.Model.extend
  viewType: App.OrderView
Run Code Online (Sandbox Code Playgroud)

那么模板可能如下所示:

{{#collection contentBinding="App.selectedAccountController.everythingSorted"}}
  {{view content.viewType contentBinding="content"}}
{{/collection}}
Run Code Online (Sandbox Code Playgroud)

然而,这并不理想,因为我们不希望模型了解视图层。相反,我们可以创建一些工厂逻辑来为模型创建视图。然后我们可以在控制器上创建一个计算属性,其中包含模型及其相应视图的数组:

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')
Run Code Online (Sandbox Code Playgroud)

模板将如下所示:

{{#collection contentBinding="App.selectedAccountController.everythingSortedWithView"}}
  {{view content.viewType contentBinding="content.model"}}
{{/collection}}
Run Code Online (Sandbox Code Playgroud)

可能有更好的方法来做到这一点。我很想听到更接近 Ember 核心的人给出解决方案。