Going back to our [last post related to best practices and roles in AngularJS], let's talk a little bit more about this showing a really small example.
A controller is the middle man!
Its main role is to talk to the Service to get the model and then make sure this model is available to our presentation layer (html).
Even in large applications, the controller should be small, compact and dumb!
Dom Manipulations should not exist in controllers, services or anywhere else but in directives!
This is another sample we ran into it some time ago…
Imagine there're 4 pages which represent the flow of an online purchase. Each of these pages displays the following progress bar: (Customer starts on first page)
As soon as the customer moves into the next page, the progress bar is supposed to show the current page highlighted. We're going to accomplish this by assigning the “active” CSS class to the corresponding “span” element.
The following JS code was in place on the same HTML file the progress bar was defined to do the switch among the different “span” elements:
Each page had the following code:
All of this code could be moved from the view into some place where it could be tested… As you have already read the very begining of this article and as you may already know neither a service nor a controller is the place to move this code to. But a directive is!
Having that said, a directive could be written in this case so that:
we can avoid dependencies on other html blocks or scope’s parents objects
we can avoid hard coded CSS selectors
We are going to write a directive to be applied to the “div” element so as to show the corresponding flow status according to the current page the user is on. The current page the user is on will be represented by an external variable (similar idea to “PAGE_NUM”).
To avoid dependency problems, we are going to pass this variable as a parameter. We don't care who changes this variable.
We only care to react when the variable (page) changes.
Our directive should look something like this:
We use ‘data-‘ prefix to make sure html validates and we do not cause IE7, 8 browsers to go into quirks mode. Very Important!!!!
We use ‘my-‘ prefix to determine this is a custom directive that belongs to our team.
Lets write the code for this. As always the test comes first:
So far we have created only one test, where after compiling the code, our directive applies the “active” CSS class to the corresponding element based on the page the user is currently on.
Having written the first test, the 3 remaining scenarios are straightforward. Below are them for your reference:
Having finished writting the test, it's now time to write the directive.
So now each html has:
Having replaced the original code, we removed the jQuery library dependency as well as the hardcoded id (“progressBar”) and CSS (“active”). As a result, now we have a reusable, independent, tested -and testable- directive.
Please note that this directive is only reusable within the same app and for that purpose, since the quantity of “span” elements (pages) and their names are fixed. We'll show you how this same directive can be written in a different way (more flexible) in the next post. Visit us shortly!