Multi-Page Form Organization


#1

Hi. I would like to know the proper organization in Ember for a multi-page user signup form. Here are my requirements:

  1. The steps/views/pages of the form should all edit the same model, and possibly even multiple models, that will be submitted to the server via ember-data once the form is completed.

  2. Pressing the back/forward buttons in the browser should move the form pages back/forwards.

  3. It is not necessary to give each form page its own URL, but if it makes it easier then that’s fine. If the user visits a URL in the middle of the form without first completing the first steps, Ember should redirect to the beginning of the form.

  4. The model data should not be passed between form pages via URL GET parameters. Lets keep the URLs somewhat clean.

Should this be implemented with a single route? Multiple routes? How should the models be stored and passed from view to view?


#2

If it helps, I’ve considered three possible approaches, but don’t know which one is better practice:

  1. Each page in the form gets its own unique route, and all routes share the same parent route/controller. The model(s) are stored in the parent controller and accessed/populated by the child routes.

  2. The entire form is stored in one route, with separate components for each step. The controller contains a currentStep property to keep track of which step it is currently displaying. To get this to work with the browser history, currentStep is a query parameter that shows up in the URL.

  3. The entire form is stored in one route almost identically to option #2, but currentStep is not a query parameter, and instead some magic code that I don’t know about yet updates the browser history whenever the user navigates to the next/previous step without actually changing the URL.


#3
  1. is not an option. In ember apps you only change the url via routes or query params.

(1) and (2) are both fine approaches to this.


#4

Multiple routes and it’s how the checkout flow for https://store.nest.com was implemented. Unfortunately, the pattern wasn’t extracted out into something reusable but it does prove it’s a possibility.


#5

I came across a similar problem some time ago. I solved it like you explained on the first approach:

I have a users/signup.js route and a users/signup.js controller. The route returns a new user (i.e. this.store.createRecord('user')) and the controller has the save() method.

I also have child routes (take users/signup/username.js as an example) and their models just return their parent’s model (i.e. return this.modelFor('user.signup')) and they make use the users/signup controller.

In the last step, I call the controller’s save() method.

It meets all the requirements you talked about:

  1. The steps edit the same model;
  2. Back/Forward buttons work;
  3. Each step has its own URL;
  4. Clean URLs.

#6

Thanks @romulomachado do you have any public repo to see this in action?