Theodo apps

Angular Multipage Form, or Sharing data in Angular

TL;DR: Sharing data in Angular

For a multipage form use a parent state for the controller and nested states for the views. A parent state can have a controller that is shared by all child views, making the data flow much easier to reason about.

If you have been using angular for a while now, you might have had to share data between states. If you did so, you probably ended up creating a service that stores the data and is then imported by several views. Even though that solution works, there are other patterns out there to share data, that sometimes seem more appropriate. One such times is when you want to make a multipage form.

If you were doing a long single page form, you would only need one controller, and no service to share data between inputs, so why should you need it in a multipage form?

In this article I will show you how to refactor a 3 step form using a service to share data, into the same form using a parent state for the controller and nested states for the views.

Even though I am showing it here as a refactoring, I now use this pattern directly for my angular forms.

Refactor your multipage form

First of all, let's take a look at the multiform page that uses a service:

See the Pen <a href="http://codepen.io/tiagojdferreira/pen/bZooYO/">Multipage form - Sharing data in angular (original)</a> by Tiago Joel Domingues Ferreira (<a href="http://codepen.io/tiagojdferreira">@tiagojdferreira</a>) on <a href="http://codepen.io">CodePen</a>.

We have 3 states, each with its own controller, and a service (formRegistry) to share the data between them. We need to always inject the service in each controller and in the second step, to be able to access the data in the service, we need to bind it to the controller. Nasty!

Learn how to apply this pattern to your Angular forms directly

Let's start refactoring!

1 - Create a parent state

To do so you need to do 2 things, create a parent state and rename the child views:

++pre>++code>.state('form', {
     abstract: true,
     url: '',
     template: '<ui-view/>',
++/code>++/pre>

Rename ++code>step1++/code> into ++code>form.step1++/code> in the states and in the ++code>$state.go('form.step1');++/code>. Repeat for ++code>step2++/code> and ++code>step3++/code>.

2 - Add a controller to the parent state

++pre>++code>.state('form', {
...
controller: 'formController as formCtrl',  
})

...

.controller('formController', function($state){        

});
++/code>++/pre>

3 - Move the code from the other controllers into the new controller. Replace all references to old controllers in the HTLM by ++code>formCtrl++/code>. Delete the old controllers.

By now your code should look like:

See the Pen &lt;a href="http://codepen.io/tiagojdferreira/pen/JKArVd/"&gt;Multipage form - Sharing data in angular (mid refacto)&lt;/a&gt; by Tiago Joel Domingues Ferreira (&lt;a href="http://codepen.io/tiagojdferreira"&gt;@tiagojdferreira&lt;/a&gt;) on &lt;a href="http://codepen.io"&gt;CodePen&lt;/a&gt;.

4 - Inside the controller, replace references to the service ++code>formRegistry++/code> by ++code>this++/code>. In the html for step2 replace ++code>formCtrl.formRegistry.animal++/code> by ++code>formCtrl.animal++/code>. Now you can safely remove the service ++code>formRegistry++/code>.

After you finish refactoring, you should have something like this:

See the Pen &lt;a href="http://codepen.io/tiagojdferreira/pen/EywvBx/"&gt;Multipage form - Sharing data in angular&lt;/a&gt; by Tiago Joel Domingues Ferreira (&lt;a href="http://codepen.io/tiagojdferreira"&gt;@tiagojdferreira&lt;/a&gt;) on &lt;a href="http://codepen.io"&gt;CodePen&lt;/a&gt;.

Summary

To sum up, we made a multipage form with a single controller, like we would do for a single page form. If you are worried about the fact that we merged N-controllers into one, remember that there is a single responsability here, that of the form. Since this responsability only concerns the form's controller, this pattern allowed us to get rid of a service whose sole purpose was to overcome a limitation of angular

Développeur mobile ?

Rejoins nos équipes