Here at Nonlinear, we're big proponents of developing best practice guides to ensuring successful project management, development and QA. Today we are offering up a look at our best practices for AngularJS:
AngularJS is a comprehensive framework that can help you deliver the website you need with productivity and quality. As is always the case with any technical framework, our team at Nonlinear follows a particular set of best practices for delivering quality projects every time; AngularJS is no exception.
While not a comprehensive list, this post outlines how we ensure better organization, fewer bugs and faster bug fixing among our AngularJS projects.
If you have lined up a big team to work on a big project, deciding on the project's structure is the first decision you'll need to make and may very well be the most important one of all. Deciding on a good structure can streamline your development process by enabling developers to quickly understand how the application is organized. A developer with a basic understanding of AngularJS concepts can look at the structure and will know right away where to find the bug fixes.
In bigger projects, due to the number of different applications sections and functionalities, we organize our files by different app sections containing all related elements to this area as subfolders.
Take care with complex expressions in HTML
The controller of a page is your dear friend. Although it's not recommended to overuse the controller, you should not keep complex expressions on your HTML code. It diminishes readability and makes maintenance substantially more difficult.
Lets take a look at a use case:
In this use case, if your user is 21 years old and is single and has a car, then you need to show him a offer.
- In our basic user interface, the user will input his age and click both select boxes to reach the offer in case of him being 21 years old (give it a try in JSFiddle)
- Your first approach to accomplishing this could be to use ng-show directive to hide and show the special offer area according to the condition:
<div if="specialOfferDiv" ng-show="user.hasCar && user.age == 21 && user.isSingle">
In this case, you are overusing your HTML to insert conditions for the special offer area to show. Your HTML should never need to know about all those conditions. So, you could improve that sending the condition checkup to the controller, as a function in the scope.
Don’t rely always on functional testing for finding problems. While developing critical areas of your application, you should develop unit tests. AngularJS eases the process of doing unit tests by providing the dependency injection mechanism and even some helpers for doing unit testing. Also, any bug fix you do you can complement with tests to ensure that the bug doesn’t appear again while you're developing or do other bug fixing, avoiding software regression.
You can reach AngularJS documentation on unit testing so you can start right away testing parts of your application: https://docs.angularjs.org/guide/unit-testing
Avoid using the controller for everything
The controller in AngularJS is a powerful concept. It has the scope, which can be accessed by the views, to retrieve data and call functions, is closely related to AngularJS OOTB directives (ng-model, ng-class, etc), but it's not the place for everything. Any code that needs to be reused again and again, shouldn't stay on the controller. As an alternative, reuse these chunks of code, creating specific filters, services, to hold this code and be requested later via Dependency Injection.
Check out this example:
The function ‘doCrazyCase’ is repeated in the two controllers, which is a mistake. You can refactor this to a specific service so you can reuse it via angularjs dependency injection.
In this second example you can see that AngularJS injects the new service ‘myStringCrazifier’ and it can be reused in both controllers.
Learn how to use the OOTB directives that come with AngularJS
A simple use case to illustrate why:
In some use cases, the information that the user inputs in a field in the pages needs to be reformatted before being sent to the server. For example, if a user inputs a telephone number as a masked number but the server requests to have it sent as a raw number. The most common approach would be getting all the saved information in the scope (after user clicks to send it) and format it before sending to the server. That's not necessarily the wrong way to do it.
But you can use the power of creating a custom parser for your field to format the input value before it's saved to the scope. The ng-model has a sequence of parsers that will parse the value that the user inputs in the field to realize validations and format it when configured.
What does that do for you?
You can reuse this formatting when you want to apply this formatter to other fields (you can apply the directive with custom behavior to any element you want) and you minimize bugs, as you understand clearly where in the application the values are being changed before saving to the scope.
Let's take a look at another use case:
An ng-class is a directive that can be used to set classes depending in a specific condition of a variable in the scope. It is not uncommon to find HTML files where the checking of the condition exists on the HTML, not harnessing the full potential of the ng-class directive.
You can see both the good and bad in this Fiddle example:
These are just some of the good practices Nonlinear uses to ensure smooth project delivery.
PS:Want to bootstrap your project with some good practices? Yeoman is a project generator which uses some of AngularJS best practices and you can try it easily with simple steps. You can find a basic tutorial on creating a AngularJS project with Yeoman on http://yeoman.io/codelab.html