Form usability is incredibly important. As one of the primary input interfaces, the usability of a form is essential to a good user experience.
When a form has very distinct sections, it may be worth separating them into multiple parts.
Checkout processes are a common example of this. They’re usually separated in personal info, shipping info, payment info and confirmation.
We’re going to create a checkout form and see how easy it is to deal with multi-step forms with Ember.
Model
We’ll create an Order model to use as an example.
(I know that model is not great, a lot of data could go into other models, but for the sake of the example, that’ll do.)
The Order model looks like this:
The parent route
Now, we’ll generate a checkout route.
We’ll edit the checkout template and add a title.
Make sure you don’t remove the {{outlet}}. It is crucial here.
On the route’s model, we’ll create and return a new Order.
If we spin up the server and go to localhost:4200/checkout, we’ll see:
We can see the title on the page and an object order in store with Ember Inspector (if you don’t have it installed, you should). Nothing too stupendous.
The child routes
Now, we’ll make the magic happen. We need to generate four child routes (checkout/personal-info, checkout/shipping-info, checkout/payment-info and checkout/confirmation).
The app/router.js should look like this:
We’ll edit the templates so we can locate ourselves and navigate between them.
The payment-info template won’t have a next link. It’ll have a submit button and after saving, we’ll redirect to confirmation.
Our navigation works and the checkout process looks like:
All together now
Now, we need to create our form and make it work seamlessly with our navigation. Each step of the checkout should edit only one order object. As we have already returned one in the parent route’s model, we only need to reuse that model in the child routes.
Update all child routes (app/routes/checkout/personal-info.js, app/routes/checkout/shipping-info.js, app/routes/checkout/payment-info.js and app/routes/checkout/confirmation.js) to look like the following:
We told Ember we’re using the same model from the parent route in all child routes. Now we’re dealing with the same object in all child routes and we can split our form into them.
The personal-info template will have all “personal” fields:
The shipping-info template will have all shipping fields:
The payment-info template will have all payment fields:
Our multi-step form is working and we’re editing only one order with it.
We now only need to submit the form, persist the data and to redirect the user to the confirmation page. We’ll use a controller to handle this for us.
Now we tell app/routes/checkout/payment-info.js to use the controller we just generated. (It’s the route that will have the button that triggers the action.)
Add a button to the template:
And create the action on app/controllers/checkout.js:
Because we don’t have a back-end set up, I just console logged Order placed! and transitioned to the confirmation route. If we had the back-end, a simple this.get('model').save() would do the job.
And finally, we can confirm some data on app/templates/checkout/confirmation.hbs:
And now our multi-step form works!
That’s wrap! Another long post, but I hope you learned how to make multi-step forms with Ember. If you have something to say, hit me up on Twitter, I’m @romulomachado_ there. If you’d like to see the complete solution, it’s on GitHub.
Share this post on Twitter or find another one to read here.