【问题标题】:Multi-step form (or multiple "pages") in one route using Ember.js使用 Ember.js 的一条路线中的多步骤表单(或多个“页面”)
【发布时间】:2014-03-04 10:53:16
【问题描述】:

我想将我的 EmberJS 应用程序的单一路径用于成为多步骤表单。这是唯一次我希望我的 URL 保持不变,所以 location: 'none' 不是一个选项(据我所知)。我在其他路由上有控制器,它们应该与 URL 紧密集成。

但在这个单一的、不变的 URL 上,我想完成以下操作:

  1. 用户回答了一些问题。
  2. 用户点击一个按钮,旧问题就会被新问题取代。
  3. 冲洗并重复直到最后一个“页面”,所有数据最终在提交时.save()-ed。

车把的工作方式真的让我陷入了循环。

我一直在翻阅文档,但实际上找不到示例。我有一种感觉,这是一个我不知道我还不知道的情况。因此,如果有人能指出我正确的方向,希望这就是我所需要的。

【问题讨论】:

    标签: ember.js


    【解决方案1】:

    您可以通过一些操作和一些定义表单状态的值来实现这一点。

    您的控制器可能有一些状态属性,如下所示。

    // Step one is default.
    stepOne: true,
    stepTwo: false,
    stepThree: false,
    

    您希望如何从一个步骤过渡到另一个步骤是一个用例问题,但您将结束更改步骤属性,就像这样。

    actions: {
      toStepTwo: function() {
        this.set('stepOne', false)
        this.set('stepOne', true) 
      },
      // But you could put this with some other functionality, say when the user answer a question.
      answerQuestion: function() {
        // Run some question code.
        // Go to next step. 
        this.set('stepOne', false)
        this.set('stepOne', true) 
      },
    }
    

    在您的模板中,您可以使用 if 帮助器封装您的内容。

    {{#if stepOne}}
      Step one
    {{/if}
    {{#if stepTwo}}
      This is step two
    {{/if}}
    

    所以在这里创建 3 步属性的原因,而不是

    currentStep: 1,
    

    是为了车把,目前你不能像这样匹配当前步骤。

    {{#if currentStep == 1}}
    

    除非你创建一个车把块助手。

    【讨论】:

    • 非常感谢!这似乎会完美地工作。这似乎有点笨拙(不是您的建议,而是在 EmberJS 中完成的方式),尽管 EmberJS 提供的所有其他东西的权衡是非常值得的。
    【解决方案2】:

    我从 MartinElvar 的 excellent answer 开始,但由于我需要在向导的每一页上验证一个表单,所以最终换了一个地方。通过使向导的每个页面成为自己的组件,您可以轻松地限制每个页面的验证。

    从控制器上的步骤列表开始:

    // app/controllers/wizard.js
    export default Ember.Controller.extend({
      steps: ['stepOne', 'stepTwo', 'stepThree'],
      currentStep: undefined
    });
    

    然后确保无论何时输入您的控制器,都会让用户跳到第一步:

    // app/routes/wizard.js
    export default Ember.Route.extend({
      setupController (controller, model) {
        controller.set('currentStep', controller.get('steps').get('firstObject');
        this._super(controller, model);
      }
    });
    

    现在您可以返回控制器并添加一些更通用的下一步/返回/取消步骤:

    // app/controller/wizard.js
    export default Ember.Controller.extend({
      steps: ['step-one', 'step-two', 'step-three'],
      currentStep: undefined,
    
      actions: {
        next () {
          let steps = this.get('steps'),
            index = steps.indexOf(this.get('currentStep'));
    
          this.set('currentStep', steps[index + 1]);
        },
    
        back () {
          let steps = this.get('steps'),
            index = steps.indexOf(this.get('currentStep'));
    
          this.set('currentStep', steps.get(index - 1));
        },
    
        cancel () {
          this.transitionToRoute('somewhere-else');
        },
    
        finish () {
          this.transitionToRoute('wizard-finished');
        }
      }
    });
    

    现在为您的向导页面定义一个组件。这里的技巧是定义与控制器中列出的每个步骤具有相同名称的每个组件。 (这允许我们稍后使用组件助手。)这部分允许您在向导的每个页面上执行表单验证。例如,使用ember-cli-simple-validation:

    // app/components/step-one.js
    import {ValidationMixin, validate} from 'ember-cli-simple-validation/mixins/validate';
    export default Ember.Component.extend(ValidationMixin, {
      ...
      thingValidation: validate('model.thing'),
      actions: {
        next () {
          this.set('submitted', true);
          if (this.get('valid')) {
            this.sendAction('next');
          }
        },
    
        cancel () {
          this.sendAction('cancel');
        }
      }
    });
    

    最后,路线的模板变得直截了当:

    // app/templates/wizard.hbs
    {{component currentStep model=model 
      next="next" back="back" cancel="cancel" finish="finish"}}
    

    每个组件都获得对控制器模型的引用,并在步骤中添加所需的数据。这种方法对我来说非常灵活:它允许您在向导的每个阶段做任何必要的疯狂事情(例如与硬件交互并等待它响应)。

    【讨论】:

    • 这对我很有帮助,迈克。谢谢!
    • 我想,一旦控制器开始移开并且事情转向服务,将这个控制器逻辑移动到一个管理进程的父组件中会很有意义,但这非常感谢 Mike。
    猜你喜欢
    • 1970-01-01
    • 2011-07-02
    • 2020-05-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-30
    • 2013-01-31
    相关资源
    最近更新 更多