我使用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}}
......还有帮助者......
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...
});
另外,这是我应该用Handlebars做的事吗?
答案 0 :(得分:5)
使用ViewStates,请参阅以下示例:
答案 1 :(得分:4)
我通过使用mixin建立自己的约定来解决这个问题。模型对应于具有相似名称的视图。例如,App.Design模型实例对应于视图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,我意识到视图可以通过使用对象上的属性来指定。我仍然真的想听听解决这个问题的“正确”方法。
答案 2 :(得分:1)
这只是我的头脑:我会为每种模型类型创建一个单独的模板/视图。例如。会有DesignView
,OrderView
等。其中每个都会指定与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核心的人提出解决方案。
答案 3 :(得分:1)
这是我用于类似场景的内容。
模特&#39;页面&#39; hasMany&#39;活动&#39;。
// App.PageModel
export default DS.Model.extend({
index : DS.attr('number'),
activity : DS.hasMany('activity', { async: true })
});
模特&#39;活动&#39;有财产&#39;类型&#39;引用哪个模板用于另一个属性&#39;配置&#39;。
中的内容// 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}}
对于type:&#39; static&#39;,它使用{{{3 mustache option}}}来呈现html字符串。
{{! static.hbs }}
{{{configuration.content}}}
其他选项要复杂得多,但仍使用&#39;进行简化。即:对于类型:&#39; multiplechoice&#39;,
{{! 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}}
对于部分内容,请记住根据您的环境考虑命名和/或文件夹结构,即&#39; _partialname.hbs&#39;或者&#39; viewname / partialname.hbs&#39;