与多个状态的把手模板

时间:2013-06-11 02:12:23

标签: ember.js handlebars.js

我正在尝试写一个有三种状态的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中的计算属性更改我的模板(同样,不可能)。所以我的问题是,有没有更好的方法来编写上面的代码,以防止代码重复通过许多小布尔标志操作手动处理状态转换?

1 个答案:

答案 0 :(得分:2)

  

对我来说这真的很难看 - 我们根据事件设置单独的布尔值,以便使用手把有目的地限制条件语法。

完全同意,这表明需要进行一些重构。

  

我想要的是一个把手结构,它接受类似Ember StateManager属性的东西(Handlebars语法不可能)。

如果你写一个自定义车把助手,这是可能的,但说实话,我不推荐这种做法。

  

或者,至少,我想根据StateManager中的计算属性更改我的模板(同样,不可能)

为什么不呢?猜测你的意思是即使你有这个属性,也不可能在没有所有布尔值的情况下改变模板。

所以我的问题是,有没有更好的方法来编写上面的代码,以防止代码重复通过大量的小布尔标志操作手动处理状态转换?

是。手把具有此限制的原因是为了防止复杂性和逻辑成为模板的一部分。例如,您需要根据某些值显示类似于3的版本。这种逻辑属于视图或控制器层。

所以看一下你的例子,模板有两个方面需要改变

  • 文字:应该是“提交”,“保存...”或“已完成!”
  • iconClassNames :空,“icon-spinner icon-spin”或“icon-check-sign”

考虑到这一点,我们可以将模板简化为:

<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。这意味着将texticonClassNames更改为要计算的属性。理想情况下,它们将根据模型对象的基础状态进行计算,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);
  }
});