【问题标题】:Handlebars template with multiple states具有多种状态的车把模板
【发布时间】:2013-06-11 02:12:23
【问题描述】:

我正在尝试编写具有三种状态的 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);
  }
});

对我来说,这真的很难看——我们根据事件设置单独的布尔值,以便使用车把故意限制的条件语法。

想要是一个handlebars 构造,它接受类似Ember StateManager 属性的东西(不能使用Handlebars 语法)。或者,至少,我想根据来自 StateManager 的计算属性更改我的模板(同样,不可能)。所以我的问题是,有没有更好的方法来编写上述代码,以防止通过大量的小布尔标志操作手动处理代码重复处理状态转换?

【问题讨论】:

    标签: ember.js handlebars.js


    【解决方案1】:

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

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

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

    如果您编写自定义车把助手,这是可能的,但老实说,我不推荐这种方法。

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

    为什么不呢?猜你的意思是即使你有那个属性,没有所有的布尔值是不可能改变模板的。

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

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

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

    • 文本:应为“提交”、“正在保存...”或“已完成!”
    • 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 成为 stateManager 的bound。这意味着将 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);
      }
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-04
      • 2013-10-11
      • 1970-01-01
      • 1970-01-01
      • 2017-07-17
      相关资源
      最近更新 更多