Подтвердить что ты не робот

Ember.js - Создание многоэтапного мастера - Как?

Мне нужно создать мастер с несколькими шагами. На каждом этапе будет отображаться форма с параметрами, и в зависимости от выбора пользователя мастер должен перейти на определенный шаг, а также сохранить пользовательские настройки (выбор), хранящиеся в некотором месте.

Эти настройки не сохраняются в модели, они относятся только к этапу создания модели.

Чтобы дать некоторый контекст, цель этого:

  • Задайте пользователю несколько вопросов относительно времени работы его бизнеса. Например: открыт ли он по выходным дням, отличается ли это летом?
  • В соответствии с ответами на эти вопросы будет отображена окончательная форма, чтобы создать модель расписания.

Вопрос в том, что было бы лучшим способом выполнить это внутри Ember?

Вот мои -Ember новички-мысли:

  • Создайте шаблон для каждого шага мастера.
  • Следите за текущим шагом. Где? Контроллер? Маршрут?
  • Отобразите эти шаблоны в outlets, которые должны отображаться динамически в соответствии с текущим шагом. Здесь я полностью потерялся. Как это сделать? Если каждый шаг имеет другой маршрут или нет?
  • Следите за ответами пользователей в контроллере .
  • Как только мастер завершит работу, загрузите шаблон формы, который будет читать пользовательские настройки, сохраненные в контроллере.

Используемые версии:

  • Ember.VERSION: 1.0.0-rc.1 application.js: 9268
  • Handlebars.VERSION: 1.0.0-rc.3 application.js: 9268
  • jQuery.VERSION: 1.9.1
4b9b3361

Ответ 1

Похоже, вы на правильном пути.

Создайте шаблон для каждого шага мастера.

Да, это хорошее начало.

Следите за текущим шагом. Где? Контроллер? Маршрут?

Будет работать либо контроллер, либо маршрут. Маршрут имеет наибольшее значение, если вы хотите, чтобы закладки для каждого шага были заклассифицированы, а для обратной/передовой работы - это, пожалуй, самое простое решение. Предположим, вы выбрали маршрут.

Покажите эти шаблоны в торговых точках, которые должны отображаться динамически в соответствии с текущим шагом. Здесь я полностью теряюсь. Как это сделать? Если каждый шаг имеет другой маршрут или нет?

Поскольку каждый шаг будет маршрутом, ember позаботится об автоматическом рендеринге соответствующего шаблона.

Следите за ответами пользователей в контроллере.

Как только мастер завершит работу, загрузите шаблон формы, который будет читать пользовательские настройки, сохраненные в контроллере.

Подумайте о том, что "закончен" как еще один шаг. Каждый шаг получает собственный контроллер, который используется для записи ответов пользователей. Последний контроллер использует "потребности" для доступа к более ранним контроллерам, чтобы настроить поведение на основе ответов на мастер.

Ответ 2

Я знаю, что это старый поток и, вероятно, не поможет OP, но stackoverflow приводит к большему количеству ответов, чем что-либо еще. Я просто написал сообщение в блоге об этом.

Посмотрите на JSBin, чтобы увидеть, что я сделал. Я опишу здесь.

Маршрут на шаг в шаблоне:

Router.map(function() {
  this.resource('wizard', function(){
    this.route('index');
    this.route('review');
    this.route('complete');
  });
});

Пользовательское вычисляемое свойство, которое изменяет значения при изменении маршрутов (в этом случае, когда шаги мастера изменяются)

import Ember from 'ember';  
var get = Ember.get;  
var computed = Ember.computed;

export function routeVal(routeVals, prop){  
    return computed('currentPath', function(){
        var currentRoute = get(this, 'currentPath');
        var routeValues = get(this, routeVals);
        for (var i = 0; i < routeValues.length; i++) {
            if (routeValues[i].route === currentRoute) {
                return routeValues[i][prop];
            }
        }
    });
}

A route-value объект:

export default Ember.Object.extend({
    route: null
    //all other props can be added dynamically
});

Контрольный микс для того, чтобы знать текущий маршрут:

export default Ember.Mixin.create({  
    needs: ['application'],
    currentPath: Ember.computed.alias("controllers.application.currentPath")

});

Контроллер ресурсов:

import CurrentRouteAware from 'path/to/mixin'; 
import {routeVal} from 'app_name/utils/macros';
export default Ember.Controller.extend(CurrentRouteAware, {
  routeValues: [
        RouteVal.create({
            route: 'wizard.index',
            step: 'Create',
            next: 'Review',
            nextTransition: 'wizard.review',
            prevTransition: 'wizard.index',
            showNext: true,
            showPrev: false
        }),
        RouteVal.create({
            route: 'wizard.review',
            step: 'Review',
            next: 'Complete',
            prev: 'Create',
            nextTransition: 'wizard.complete',
            prevTransition: 'wizard.index',
            showNext: true,
            showPrev: true
        }),
        RouteVal.create({
            route: 'wizard.complete',
            step: 'Complete',
            next: 'Make Another',
            prev: 'Review',
            nextTransition: 'wizard.complete',
            prevTransition: 'wizard.review',
            showNext: false,
            showPrev: true
        })
    ], 
    nextButton: routeVal('routeValues', 'next'),
    prevButton: routeVal('routeValues', 'prev'),
    nextTransition: routeVal('routeValues', 'nextTransition'),
    showButtons: routeVal('routeValues', 'showButtons'),
    prevTransition: routeVal('routeValues', 'prevTransition'),
    showNext: routeVal('routeValues', 'showNext'),
    showPrev: routeVal('routeValues', 'showPrev'),
    actions: {
        next: function(){
            this.transitionToRoute(this.get('nextTransition'));
        },
        prev: function(){
            this.transitionToRoute(this.get('prevTransition'));
        }
    }
});

Подумайте о значении объекта маршрута как значения: "Когда маршрут равен routeVal.route, следующие свойства будут иметь эти значения", например "Когда текущий активный маршрут" wizard.index ", следующий переход -" мастер ". обзор", следующий текст кнопки - "Обзор", предыдущая кнопка должна быть скрыта и т.д.

И наконец, ваш шаблон ресурса:

<div class="wizard" id="wizardIllustration">
    {{form-wizard steps=routeValues currentPath=currentPath}}
  <div class="actions">
  {{#if showPrev}}
    <button type="button" {{action 'prev'}}class="btn btn-default btn-prev"><span class="glyphicon glyphicon-arrow-left"></span>{{prevButton}}</button>
    {{/if}}
    {{#if showNext}}
    <button {{action 'next'}}type="button" class="btn btn-default btn-next" >{{nextButton}}<span class="glyphicon glyphicon-arrow-right"></span></button>
    {{/if}}
  </div>
  <div class="step-content">
    {{outlet}}
  </div>

</div>

Вы можете посмотреть на jsbin, для чего был компонент-макет формы (просто обтекание css для мастеров Fuelux, который поддерживает активный класс на правильном шаге, основанном на маршруте). Тело мастера является шаблоном для каждого из подпрограмм. Текст кнопки next/prev изменяется в зависимости от маршрута, как и их переходы (так как переход зависит от текущего состояния мастера). Это более или менее FSM

Ответ 3

Отвечая на старый вопрос, если кому-то нужны ответы.

Вы можете использовать что-то вроде этого Многоступенчатая форма (или несколько страниц) в одном маршруте с использованием Ember.js

это использует 1 маршрут, и каждый шаг/страница отображается или скрывается с помощью {{#if}} Чтобы ответить на вопрос Nino, когда я это осуществил, у меня был объект в контроллере, который отслеживал все значения полей формы и обновлял его, когда я нажимаю дальше. Когда вы попадаете на последнюю страницу, на которую вы отправляете, вы можете просто подключить этот объект к своей функции отправки в виде списка, например,

submitSurvey: function() {
  var survey = this.store.createRecord('survey', this.get('surveyObj'));
  // surveyObj contains all the form field values that you've been
  // keeping track of everytime you go from one step to another
  survey.save();
  this.transitionToRoute('somewhere'); // go somewhere after submitting the form
  this.set('firstPage', true); // make first page the page to show
  this.set('lastPage', false);
  this.init();
  // constructor init contains code that empties all the form fields alternatively
  // you can create a separate function instead of using init
}

Хорошо для простой реализации многостраничной формы. Проблема у меня с этим: у меня есть код jQuery UI, который подключается к представлению didInsertElement, и он работает именно так, когда я перехожу с одного шага в другой и возвращаюсь (на каждой странице есть кнопки "next" и "prev" ), я считаю, что независимо от того, какой код, который был запущен в didInsertElement, будет отменен. Он, как кусок html-кода, был не просто скрыт и перепрограммирован. Он был перезагружен, и, таким образом, все эффекты исчезли.