我正在尝试写一个有三种状态的Ember视图。具体来说,提交按钮从“提交”转换为“保存...”到“完成!”有很多方法可以实现这个目标,但我想知道从Ember的角度来看,如果不编写糟糕的代码,“最佳实践”是什么。
目前我有以下代码:
UiControls.SubmitButton = Ember.View.extend({
template: function() {
var template = '{{#if view.isNotStarted}}Submit{{/if}}';
template += '{{#if view.isStarted}} <i class="icon-spinner icon-spin"></i>Saving...{{/if}}';
template += '{{#if view.isFinished}} <i class="icon-check-sign"></i>Finished!{{/if}}'
return Ember.Handlebars.compile(template);
}.property(),
isNotStarted: true,
isStarted: null,
isFinished: null,
classNames: ['btn', 'btn-green'],
isDisabled: false,
click: function(){
if (!this.get('disabled')){
this.set('isNotStarted', false);
this.set('isStarted', true);
this.set('isFinished', false);
this.timer();
}
},
/* Simulates a server call */
timer: function(){
(function(self){
setTimeout(function(){
self.set('isStarted', false);
self.set('isFinished', true);
}, 500);
})(this);
}
});
对我而言,这真的很难看 - 我们根据事件设置单独的布尔值,以便使用手把有目的地限制条件语法。
我想要的是一个把手结构,它接受类似Ember StateManager属性的东西(Handlebars语法不可能)。或者,至少,我想根据StateManager中的计算属性更改我的模板(同样,不可能)。所以我的问题是,有没有更好的方法来编写上面的代码,以防止代码重复通过许多小布尔标志操作手动处理状态转换?
答案 0 :(得分:2)
对我来说这真的很难看 - 我们根据事件设置单独的布尔值,以便使用手把有目的地限制条件语法。
完全同意,这表明需要进行一些重构。
我想要的是一个把手结构,它接受类似Ember StateManager属性的东西(Handlebars语法不可能)。
如果你写一个自定义车把助手,这是可能的,但说实话,我不推荐这种做法。
或者,至少,我想根据StateManager中的计算属性更改我的模板(同样,不可能)
为什么不呢?猜测你的意思是即使你有这个属性,也不可能在没有所有布尔值的情况下改变模板。
所以我的问题是,有没有更好的方法来编写上面的代码,以防止代码重复通过大量的小布尔标志操作手动处理状态转换?
是。手把具有此限制的原因是为了防止复杂性和逻辑成为模板的一部分。例如,您需要根据某些值显示类似于3的版本。这种逻辑属于视图或控制器层。
所以看一下你的例子,模板有两个方面需要改变
考虑到这一点,我们可以将模板简化为:
<i {{bindAttr class="view.iconClassNames"></i>{{view.text}}
并将属性添加到视图
UiControls.SubmitButton = Ember.View.extend({
template: Ember.Handlebars.compile('<i {{bindAttr class="view.iconClassNames"></i>{{view.text}}'),
classNames: ['btn', 'btn-green'],
isDisabled: false,
text: "Submitted",
iconClassNames: "",
click: function(){
if (!this.get('disabled')){
this.set('text', 'Saving...');
this.set('iconClassNames', 'icon-spinner icon-spin');
this.timer();
}
},
/* Simulates a server call */
timer: function(){
(function(self){
setTimeout(function(){
this.set('text', 'Finished!');
this.set('iconClassNames', 'icon-check-sign');
}, 500);
})(this);
}
});
这适用于模拟,但并不理想。你真的希望text和iconClassNames为bound
到stateManager。这意味着将text
和iconClassNames
更改为要计算的属性。理想情况下,它们将根据模型对象的基础状态进行计算,click()
将在控制器上定义,但对于模拟,它将是这样的:
UiControls.SubmitButton = Ember.View.extend({
template: Ember.Handlebars.compile('<i {{bindAttr class="view.iconClassNames"></i>{{view.text}}'),
classNames: ['btn', 'btn-green'],
isDisabled: false,
state: 'new',
text: function() {
//return appropriate button text based on state
}.property('state'),
iconClassNames: function() {
//calculate text based on state
}.property('state'),
/* Simulates a server call */
click: function(){
if (!this.get('disabled')){
this.set('state', 'saving');
this.timer();
}
},
/* Simulates a server call */
timer: function(){
(function(self){
setTimeout(function(){
self.set('state', 'finished');
}, 500);
})(this);
}
});