How to Work with AngularJS – The Absolutely Complete Guide

ByMatheus Lima in

With the recent growth of Concrete Solutions, we are working on a series of posts to explain the way we work with the technologies we use most. The idea is to guide both new “concrete” and readers who are interested in our format. Recently, Thiago Lioy made this post with our iOS practices. Today, it’s time to talk about AngularJS.

Motivation

There are a number of JavaScript frameworks currently available. So why should you use AngularJS instead of others?

Modularization

Modularization facilitates the development, configuration, and your application’s testing. AngularJS comes with a built-in Dependency Injection engine, for example, that turns the task of dividing your application into small modules into something trivial.

Two-way Data Binding

One of the most controversial features of AngularJS is Two-way Data Binding. Although very useful and one of the great factors for the success of the framework in the beginning, it can present performance problems if it is not used correctly.

Extensibility

Being able to extend HTML with AngularJS, using directives, is the most incredible feature of the framework. Policies are powerful tools for modifying and manipulating the DOM, in addition to having the ease of reuse throughout the application.

Tools

Sublime Text

The most popular editor for developing applications with AngularJS it’s still Sublime Text. In addition to being lightweight and easy to use, it has a package (plugin) specific to AngularJS.

Jasmine

Jasmine was developed for use in behavior-driven development (BDD), but is generally used in AngularJS for unit testing and TDD (test-driven development).

Karma

Karma is a runner test done for AngularJS (although you can currently use it with other JavaScript frameworks). The main goal of Karma is to automate the tests in several browsers with a simple command. One of the advantages is that it supports several types of tests, such as unit testing, integration and E2E.

Bower

Bower, created as an open source Twitter project, was developed to make it easier to use libraries and packages in a web project. You can even develop your own packages and distribute them in different projects easily.

Grunt

On several occasions, we developers face repetitive tasks that can be easily automated. This is where Grunt comes in. It is used for: minification, JavaScript linting and build generation.

Application example

Setup

To begin our setup, we need to install Bower. Assuming you already have NPM installed, you only need to:

$ npm install -g bower

Now create a folder called app-example, enter it and create a Bower configuration file:

$ mkdir app-exemplo
$ cd app-exemplo
$ bower init

Accept all defaults and your bower.json should be close to this:

/// bower.json

{
 "name": "app-exemplo",
 "version": "0.0.0",
 "authors": [
  "Matheus Lima <matheusml90@gmail.com>"
 ],
 "license": "MIT",
 "ignore": [
  "**/.*",
  "node_modules",
  "bower_components",
  "test",
  "tests"
 ]
}

Now, to install AngularJS, we must add the dependency in the Bower. And to do this just type:

$ bower install --save angular

Note that a folder named bower_components has been created. In this folder will be all the dependencies of the Bower. In addition, the bower.json file was automatically modified, thus:

/// bower.json

{
 "name": "app-exemplo",
 "version": "0.0.0",
 "authors": [
  "Matheus Lima <matheusml90@gmail.com>"
 ],
 "license": "MIT",
 "ignore": [
  "**/.*",
  "node_modules",
  "bower_components",
  "test",
  "tests"
 ],
 "dependencies": {
  "angular": "~1.4.3"
 }
}

We strongly recommend adding the bower_components folder in .gitignore. To do this, first create the file:

$ touch .gitignore

And within .gitignore, we need to leave it this way:

/// .gitignore
Bower_components
Now we need to create the index.html of our application:

$ mkdir app
$ cd app
$ touch index.html

And, in it, import the minuted file from AngularJS that came from Bower, so that the application can work.

/// index.html
<html>
 <head>
  <title>AngularJS</title>
 </head>
 <body>
  <h1>AngularJS</h1>
  <script type="application/javascript" src="../bower_components/angular/angular.min.js"></script>
 </body>
</html>

We also need a server to run our application and see that our index.html works. Let’s use the http-server, which can be downloaded by NPM:

$ npm install -g http-server
$ cd ..
$ http-server

Now, just go to http: // localhost: 8080 / and we should see something close to this:

To standardize and facilitate application startup and testing, we need to configure a package.json (which is used by NPM):

$ npm init

Accept all defaults and it should look similar to this:

//package.json
{
 “name”: “app-exemplo”,
 “version”: “1.0.0”,
 “description”: “”,
 “main”: “index.js”,
 “scripts”: {
      “test”: “echo \”Error: no test specified\” && exit 1"
 },
 “author”: “”,
 “license”: “ISC”
}

So that we can start the application with just one command, we will edit the file adding only one line:

///package.json
{
  “name”: “app-exemplo”,
  “version”: “1.0.0”,
  “description”: “”,
  “main”: “index.js”,
  “scripts”: {
      "start": "http-server ./app -a localhost -p 8080",
      “test”: “echo \”Error: no test specified\” && exit 1"
   },
  “author”: “”,
  “license”: “ISC”
}

With this modification, we can run the application as follows:

$ npm start

And accessing http: // localhost: 8080 / you should see this:

Architecture

Now that we have done the basic setup, we can start with the AngularJS application architecture model that we use here at Concrete Solutions.

  1. Structure

All of our Controllers, Services, Factories and Policies follow the same structure:

(function() {
    'use strict';
    angular
        .module('app')
        .controller('AuthController', AuthController);
     
    function AuthController() {
        /* código */
    }
})();

If you do not understand the first and last lines, this very common pattern in projects with JavaScript is called IIFE. I recommend this text for you to understand all the details of it.

Another very common standard we use is ‘use strict’, which serves briefly to improve the process of error checking in code.

And lastly, it’s worth noting that we use a Top-Down approach, where statements are at the top of the file, and implementation is under it.

  1. 2 Dependency Injection

We use the $inject method to do DI:

(function() {
    'use strict';
    angular
        .module('app')
        .controller('AuthController', AuthController);
    AuthController.$inject = ['$location', 'AuthService'];
     
    function AuthController($location, AuthService) {
        /* código */
    }
})();

The advantage is the ease in minification of files (since the dependencies are brought as Strings).

  1. 3 Controllers
function AuthController($location, AuthService) {
    var vm = this;
    vm.login = login;
    function login(email, password) {
        AuthService.login(email, password).then(function() {
            $location.path('/');
        });
    }
}

We try to keep Controllers as lean as possible, with little logic, and following the Single Responsability Principle. This way they are easier to maintain, read and test.

We also use the ControllerAs pattern with the vm variable, proposed by John Papa. One of the advantages is the no need to import the $scope in the Controllers.

  1. 4 Communication with the Back-End

We prefer to encapsulate $http calls in Services:

function AuthService($http) {
    this.login = function(email, password) {
        var request = {
            username: email,
            password: password
        };
        return $http.post(url, request);
    };
}

One focus of this approach is the Separation of Concerns. That is, it is not the responsibility of the Controllers to deal with the logic of communication with the Back End, but rather a service done only to deal with it.

  1. 5 Factory

One of the ways to share data in an application with AngularJS is the use of Factories. Since they are singletons, the data is not lost in the context switch. A good use case is the creation of a Session:

function Session($cookieStore) {
    return {
        create: create,
        destroy: destroy,
        isAuthenticated: isAuthenticated
    };
     
    function create(id) {
        $cookieStore.put('session', id);
    }
    function destroy() {
        $cookieStore.remove('session');
    }
    function isAuthenticated() {
        !!$cookieStore.get('session');
    }
}

In this example, we can access from any Controller the user’s session and verify whether it is authenticated or not.

A recurring question is the difference between Factories and Services, which I explained earlier in this article.

  1. 6 Directives

As well as Controllers, the Directives should be developed with Single Responsibility Principle in mind. If a Directive solves multiple problems at the same time, it will hardly be reused and will lose all sense of existence (which is just reuse).
The following example shows a directive that gives focus to an input:

function NgFocus($timeout) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            $timeout(function() {
                element[0].focus();
            }, 0);
        }
    };
}

Note that the Directive in question has only one purpose. If it, besides giving focus to the input, had to add the green color in the background, would certainly lose the reuse in most cases.

A good text on Directives is this one, from Todd Motto.

Continuous Delivery

It is common to invest some sprints early in the projects to architect the infrastructure that will support the developers of the first line of code until the last. This means building and structuring continuous integration, continuous deployment, and automating the development and support processes. The main advantages of Continuous Delivery are:

  • Increased transparency;
  • Increased feedback;
  • Frequent releases;
  • Increased confidence in each delivery;
  • Developers can focus more on code quality and less on builds and deploys.

To automate our IC process, we chose Jenkins as a tool. First we must decide what Jenkins should do in the deployment process, which can be summarized in 6 commands:

$ npm install grunt -g
$ npm install bower -g
$ npm install
$ bower install
$ npm test
$ grunt dev
  1. Install Grunt
  2. Install Bower
  3. Install all NPM packages
  4. Install all Bower packages
  5. Run the tests using Karma
  6. Generating Build Using Grunt

After this procedure, Jenkins generates a test coverage report (which can be configured by Karma in this way):

This report has great utility to check the quality of the code throughout the project progress.

Final Comments

For those who still have questions, a good tip is my series on AngularJS on YouTube, which goes from the first steps to the construction of advanced directives:

If you have any criticism or suggestion contact me on Twitter or leave a comment here below. And if you liked the text, share it with anyone who might be interested!

Leave a comment! 0

0 comentário

Comentários

Your email address will not be published. Required fields are marked *

Commenting asAnônimo

read more