使用Ember.js在一个路线中的多步骤表格(或多个"页面")

Don*_*Don 7 ember.js

我想将我的EmberJS应用程序的一条路线用于多步骤形式.这是我希望我的URL保持不变的唯一时间,因此location: 'none'不是一个选项(据我所知).我在其他路由上有控制器,它们与URL紧密集成.

但是在这个单一的,不变的URL我想完成以下内容:

  1. 用户回答了一些问题.
  2. 用户单击按钮,旧问题将替换为新问题.
  3. 冲洗并重复,直到最后的"页面",最后.save()提交所有数据.

把手的工作方式真的让我在这上面循环.

我一直在倾注文档,但无法真正找到一个例子.我觉得这是一个我不知道还不知道的情况.所以,如果有人能指出我正确的方向,希望这就是我所需要的.

Mik*_*ost 26

我从MartinElvar的优秀答案开始,但由于我需要在向导的每个页面上验证表单,所以我在另一个地方结束了.通过使向导的每个页面成为自己的组件,您可以轻松地约束每个页面的验证.

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

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

然后确保无论何时输入控制器,都会将用户退回到第一步:

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

现在您可以返回控制器并添加一些更通用的next/back/cancel步骤:

// 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');
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

现在为向导的页面定义一个组件.这里的技巧是定义每个组件与控制器中列出的每个步骤相同的名称.(这允许我们稍后使用组件助手.)这部分允许您在向导的每个页面上执行表单验证.例如,使用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');
    }
  }
});
Run Code Online (Sandbox Code Playgroud)

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

// app/templates/wizard.hbs
{{component currentStep model=model 
  next="next" back="back" cancel="cancel" finish="finish"}}
Run Code Online (Sandbox Code Playgroud)

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

  • 迈克,这非常有帮助.谢谢! (2认同)

Mar*_*var 10

您可以通过某些操作实现此操作,并使用一些值来定义表单的状态.

您的控制器可能具有以下某些状态属性.

// Step one is default.
stepOne: true,
stepTwo: false,
stepThree: false,
Run Code Online (Sandbox Code Playgroud)

您希望如何从一个步骤转换到另一个步骤,这是一个用例问题,但您将结束更改步骤属性,如此.

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) 
  },
}
Run Code Online (Sandbox Code Playgroud)

在您的模板中,您可以使用if帮助程序封装您的内容.

{{#if stepOne}}
  Step one
{{/if}
{{#if stepTwo}}
  This is step two
{{/if}}
Run Code Online (Sandbox Code Playgroud)

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

currentStep: 1,
Run Code Online (Sandbox Code Playgroud)

是为了把手,目前你无法匹配当前的步骤.

{{#if currentStep == 1}}
Run Code Online (Sandbox Code Playgroud)

除非你创建一个把手块助手.