我正在使用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...
});
另外,这是我应该想用车把做的事情吗?
请使用 ViewState,请参阅以下示例:
http://jsfiddle.net/rsaccon/AD2RY/
我通过使用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,我意识到视图可以通过在对象上使用属性来指定。 我仍然非常想听听解决这个问题的"正确"方法。
这只是我的头顶:我会为每个模型类型创建一个单独的模板/视图。 例如,会有DesignView
、OrderView
等。其中每个都将指定要与 templateName 一起使用的模板(所有代码 coffeescript(:
App.DesignView = Em.View.extend
templateName: 'design'
App.OrderView = Em.View.extend
templateName: 'order'
每种类型的所有自定义呈现都将在视图/模板中完成。
此时,我们需要一些模板逻辑来决定为每个项目显示哪个视图。最简单的方法是将视图类型存储在模型上。
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}}
可能有更好的方法可以做到这一点。我很想听到更接近余烬核心的人给出解决方案。
这是我在类似场景中使用的。
模型"页面"有许多"活动"。
// 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 mustache 选项}}} 来呈现 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"或"viewname/partialname.hbs">