How to Learn AngularJS - Your AngularJS Sherpa

Sherpa

Learning AngularJS can be complex. There are an overwhelming number resources available on the web. The blog posts can be conflicting and confusing, and a simple google search can turn up 5 articles all describing the same thing in a completely different way.

This guide is written to be your roadmap; your personal guide of how to learn AngularJS. We’ll we’ll through the basic concepts of AngularJS in a logical, conceptual order. This post is intended to be the first post to read when starting to learn AngularJS. Use this post as your guide and you’ll be mastering Angular in no time. Let’s get started!

You might be asking “what is AngularJS anyway?” AngularJS is a javascript library that provides tools for writing rich browser applications. Even though there are a seemingly endless number of articles about the different components of AngularJS, the basics of Angular can be broken down into 5 major components:

Once we have a basic understanding of these five basic concepts, learning Angular will be no trouble at all. We’ll explain each one of those things below.

But before we explain the details of Angular, it’s useful to ask why should we use AngularJS? Why not use straight JavaScript or a library like jQuery?

Direct Javascript

Let’s take a simple example and show the differences. In this example, we’re going to have an input form that takes a user’s name. We’re going to show that name in the HTML as the user types.

With straight javascript, we tell our input form to call the function updateOutput every time the onkeyup event is fired. The element passes itself (this) as the argument to that function.

JS Bin

In updateOutput we search for the #output element and then set the innerHTML of the output element to the value of our input elem.

When designing programs, it’s important to think about how tightly dependent different parts of the system are to each other. In this example, the input “knows” what function it has to call to send behavior and the updateOutput function “knows” what DOM element id it needs to send data back to. This style of coding will break if we change the selector names and, more importantly, it makes it really hard to reuse the code.

As the code and the view are so dependent on the other not changing, we say we have a “high coupling” between the view and the code, which make it difficult to update and maintain the components of our application.

UJS and jQuery

Developers realized that this style of coding quickly becomes unmanageable. The concept of “unobtrusive javascript” (UJS) was developed. One of the main ideas behind unobtrusive javascript is that the purpose of markup is to describe a document’s structure, not it’s functionality.

Anecdotally, for many years everyone who adhered to UJS used jQuery or a similar library to bind the markup to behaviors. Typically, when we’re using jQuery and we want to make a change in a page, we use a “selector” to search for an element on the page. Then we directly modify that element and the page is updated.

Here’s an example: JS Bin

In this example, we search through our DOM and find the element with the id #your-name and then we attach a behavior to the input event. Then if we want to show the name, we need to have a place to put it. So we search the DOM again and find the element with the id #output and then we set the inner html to "Hello " + name.

This style of directly manipulating DOM elements is referred to as an “imperative” style.

The idea that markup should be used to describe document structure and not functionality is an interesting one. It turns the problem of two-way coupling between the views and the code into a one-directional coupling where you have hard-coded element IDs/CSS classes in the code.

Also, there are many of cases in which it’s useful to use markup to define behaviors. For instance, when you use a template you often say “show this variable here” or “repeat this list of things here”. By defining some behaviors in the markup, we can actually bring clarity to how a view will be used. Of course, this benefit is only a net positive as long as we don’t introduce unnecessary coupling.

One of the biggest problems with building web apps with jQuery is that we spend much of our time in our code munging with markup. Markup is really just a view of our data so wouldn’t it be nice if our code only operated on data and our views updated on their own?

AngularJS example

These are the sort of problems that AngularJS aims to solve. Let’s implement our example using AngularJS.

JS Bin

In this example we tell Angular that we want to create an app called myApp. On the input tag, we bind the value of the input to the variable name using the attribute ng-model. To show the value of name in the view, we put {{name}} in the HTML (also known as binding the value of name to the view). Angular treats the “mustache” ({{}}) tags as a template and keeps the value updated as the input tag changes.

It’s important to note that in the Angular version, we’re not looking up elements by a selector and then directly manipulating the HTML. Instead, we’re declaring where the variables should be attached and then Angular takes care of the plumbing for us.

The angular way of developing applications dictates that we take care of the data and angular will take care of the DOM manipulation.

This style of changing DOM elements is referred to as a “declarative” style.

What are AngularJS directives?

In order to work with Angular, we’ll need to understand the concept of directives.

A good way to understand directives is by way of analogy. Think for a moment about how web pages are created: we write HTML tags and each tag defines a different behavior. When we use <ul> and <li> tags, we’re telling the browser we want an unordered list. When we use HTML5 <video> or <audio> tags, we’re telling the browser we want a video or audio track to be displayed.

But there are only a finite number of HTML tags that the browser knows how to interpret. What if we wanted a <weather> tag to show the weather? What about a <login> tag to show our user login panel? Directives give us the power to create our own HTML elements. That is, directives let us specify custom DOM elements (or attributes) and attach behaviors to them.

A directive is simply a function that we run on a DOM element to give it added functionality. In Angular, we’ll use directives everywhere.

This is important to realize: when looking at the markup of an Angular app, all of the ng- tags are Angular provided directives.

For instance, we can use the ngClick directive to tell an element to run a function when it’s clicked. For instance:

1
2
3
<button ng-click="runWhenButtonClicked()">Click me</button> <!-- Or another element --> <div ng-click="runWhenDivClicked()">No click me instead</div>

In the example above, the ng-click HTML attribute is a directive that adds an event listener to the click event to the <button> and the <div>. There are a lot of built-in directives provided by Angular.

When we talk about directives, we’ll use lowerCamelCase method (e.g. ngClick) to refer to the directive. This is because in the AngularJS source code it is defined as a function called ngClick. However, when we use a directive in HTML we use “kabob case” (e.g. ng-click). Basically: ngClick and ng-click refer to the same thing, AngularJS automatically converts between the two. It can be a little confusing at first, but the idea is that it makes each code look better in context.

Directives are what makes Angular so powerful and part of what makes Angular declarative. Angular comes packed with a lot of useful built-in directives that give us the ability show or hide elements, submit and validate forms, act on click events, etc.

For instance, we can show or hide elements using the ngShow and ngHide directives:

1
2
3
<a ng-click="shouldShowDiv = !shouldShowDiv">Show content below</a> <div ng-show="shouldShowDiv">This div will be shown only if <em>shouldShowDiv</em> is true</div> <div ng-hide="shouldShowDiv">This div will be hidden if <em>shouldShowDiv</em> is not true</div>

The Angular community has built many directives for all sorts of different functionality.

It is simple to write our own directives. We’ve written a detailed post on how we can build our own directives.

To summarize: Directives make it possible to extend HTML with our own functionality.

Learn more about directives

Expressions

When we’re using directives in our markup, we can pass arguments to our directives. As we saw in the above example, the ng-click="shouldShowDiv = !shouldShowDiv" usage of the ngClick directive is actually setting a variable. Angular is taking the argument of the directive and evaluating it (almost) as JavaScript.

These expressions give us a lot of flexibility and power with our directives. We can set variables, call functions, read variables, do math, etc. etc. In fact, we can use angular expressions all over the place in angular. We can use them in template bindings as well:

1
2
3
4
<div ng-init="count = 0"> <a ng-click="count = count + 1">Add one</a> <h3>Double the count is: {{ 2 * count }}</h3> </div>

How Angular Boots

It’s important to have a rough mental model about what Angular is actually doing when our page loads. When we include the Angular javascript into our HTML page, it will attach a method to the DOMContentLoaded event (this means that Angular will run when the page is done loading). When the page has loaded, Angular will visit every element in your HTML document (i.e. it will traverse every element in the DOM). If Angular visits an element which contains a directive it will attach a behavior to it.

The very first directive Angular needs to find is the ngApp directive. Angular will bind our application to the element where it finds the ngApp directive.

For instance, if our HTML page looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!doctype html> <html> <head> <title>Bare HTML page</title> </head> <body> <div id="app" ng-app> <h1>Hello from Angular</h1> </div> <footer> &copy; Fullstack.io, LLC. </footer> </body> </html>

Angular will find the ngApp directive placed on the <div> element. The Angular app is loaded on the <div> element.

Why does it matter which element our app is “on”? Angular operates by attaching itself to particular elements and then only applies functionality to child elements.

This means that our Angular app above cannot set the <title> of the page. It cannot modify any element that is a parent or a sibling. In the example above, this means that our angular app cannot change the footer, nor the head element or any element that’s outside of the <div id="app" ng-app> element.

This means that we can use other frameworks alongside of Angular. This feature makes it easy to introduce Angular even for subcomponents of our pages.

More often than not, we’ll want to define a custom angular app instead of the default one provided by ngApp. We can declare that we want to use a custom angular module by giving a name as an argument to the ngApp directive.

That is, we would change the div above from:

1
<div id="app" ng-app>

to

1
<div id="app" ng-app='myApp'>

This let’s us reference the module myApp within our javascript code.

Rather than having an empty div within ngApp directive as we did above, we can do this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!doctype html> <html> <head> <title>Bare HTML page</title> </head> <body> <div id="app" ng-app='myApp'> <h1>Hello from Angular</h1> </div> <footer> &copy; Fullstack.io, LLC. </footer> </body> </html>

Now, Angular will look for the Angular app called myApp and throw an error to let us know if it cannot find it.

Learn more about ngApp

Modules

Once we get to our javascript code, wow do we tell Angular where our angular app is? We need to define it using the angular.module() API. There are two main operations when dealing with a module:

  1. creating a new module (i.e. the “setter”) or
  2. getting a reference to an existing module (i.e. the “getter”)

When we want to create a module we use the setter arguments:

1
angular.module('myApp', []);

When we want to get an existing module we use the getter arguments (i.e. no arguments):

1
angular.module('myApp');

The only difference between the two is that the setter takes an array as the second argument. We’ll talk more about that second argument later in the post.

Once we’ve created the module myApp, we can assign the app to a particular place in our code by using the ng-app directive. For instance, if we have the following html:

1
2
3
4
5
6
7
8
<html ng-app="myApp"> <head> <!-- etc. --> </head> <body> <!-- etc. --> </body> </html>

myApp is essentialy the “main” module for the page and the app will be automatically started (also known as bootstrapped) for us when the page is done rendering.

A module, in Angular terms is simply a collection of Angular objects that define a set of functionality.

We can think about a car as a collection of modules. From the driver’s perspective, the car is an automobile that works by turning a steering wheel and pushing some pedals. The car consists of independent modules such as the seat belts, the engine, the wheels, etc. that all work together doing their own individual jobs.

Because each component’s functionality is limited, it’s easy to test and different companies can make different components. For instance, the wheel manufacturer doesn’t need to worry about how the brakes work. They can simply focus on making a tire that’s dependable. The wheel can be independently tested and “included” as a component of the car.

Angular modules work in a similar way. We can include different components of an Angular app to make our Angular app. We can write little components that are easily testable and maintainable as well as keeping their intent obvious.

Learn more about modules:

Scopes

The next concept we need to understand when learning Angular is the concept of scopes. AngularJS uses scopes to communicate between components - particularly between our javascript and our HTML. Scopes are the glue between our code and what the browser renders.

For example, say we want to show a welcome message to a user. We can use the $scope variable in our JavaScript code to make the user variable accessible to our view, the HTML:

1
2
3
4
5
6
angular.module('myApp') // <-- This is the getter function for a module previously defined .run(function($rootScope) { $rootScope.user = { email: '[email protected]' } });

Now the HTML for our angular app can access the user variable in the view and bind it in our view.

1
<span>Welcome back {{ user.email }}</span>

When we say binding in Angular, we mean any value that is showing in the view. This happens primarily with data that is shown in the view using the template syntax {{ }}. In case you’re wondering, the template syntax works by using a directive (the ng-bind directive).

When the view loads up, our Angular app will look for the user variable in the $scope object and display it’s email attribute. This is a powerful concept: we assigned a variable user on $rootScope and Angular made this variable accessible to our view automatically.

An important thing to note is that this binding goes both ways. Our view can change the value of a variable. For instance, we can type a message in an input box (using the ngModel directive) and it will change the message in our JavaScript. Try typing in the input in this example:

JS Bin

In the above example, we’re setting the user object on the $rootScope object. When we change the value of the input text field, the value of user.email changes in our $rootScope. Because $rootScope is also bound to our view, Angular automatically updates the view.

Angular has many scopes

A powerful (but potentially confusing) feature of Angular is that you can have many scopes in your Angular application. The $rootScope is the top level scope for the rest of our application.

That means that anywhere in the view (i.e. all children elements under the DOM element with the ngApp directive) we can reference variables that are on the $rootScope object.

However, if we overuse this one $rootScope object, we could end up putting a lot of information on a single scope. If we put every variable on a single scope, then we don’t have any advantage over just using global variables; in a large, complex application we’ll end up having collisions with data on the scope and the code can easily get confusing. To prevent this, Angular provides the ability to organize scopes by using parent/child relationships.

Whats with the $dollar sign? AngularJS uses the dollar sign $ as a prefix for many Angular built-in functions and objects. Using $ as a naming convention acts as a namespace for Angular-reserved keywords. Don’t use a $ prefix when naming your services or you may run into conflicts with the core library.

Just like our DOM elements are nested in each other, scope objects can be nested. In the same way the HTML tags can have a parent, scopes can have a parent. When Angular looks up the value of a variable it will look at the current scope and then look “upwards” for the variable in any of the parent scopes.

Angular creates scopes in a variety of situations. For instance, a child scope is created for every controller in our app.

We haven’t talked about controllers yet, but we will in the next section.

But before we move on to controllers, we want to point out something that might not be obvious at first glance: a scope is a plain old javascript object (also known as a POJO). Although a scope does have functionality that makes it really useful, it isn’t magic. Scopes are javascript objects just like everything else in our program.

Summary: scopes are a way to organize key-value pairs without polluting a global namespace.

Learn more about scopes:

Angular Controllers

While directives are typically used on a single DOM element, Angular uses the concept of controllers to organize functionality across a group of DOM elements.

A controller is a bit of code that defines functionality for a part of the page.

Take a look at this example:

1
2
3
4
5
6
angular.module('myApp') .controller('HomeController', function($scope) { // We have access to this new // $scope object where we can place // data and functions to interact with it });

Now we have a controller defined, we can place it on the page using the ngController directive, like so:

1
2
3
4
5
6
<div ng-controller='HomeController'> <!-- In here, we have access to the $scope object defined by the HomeController --> </div>

Now, instead of placing all of our functionality on the special $rootScope object, we place can place it on the HomeController’s $scope object and keep our $rootScope clean.

The benefit of creating a new scope is that we’re able to keep variables and data contained to this specific part of the page. We can define a new variable without it polluting or conflicting with another part of the page.

Technically, every time that we create a new controller, Angular creates a new $scope object underneath the parent scope. (In this case the parent is $rootScope.)

We use the word “underneath” because scopes are nested. When Angular tries to lookup the value of a variable, if it doesn’t find the variable in the current scope then it will search the parent scope (until it reaches the $rootScope) with one exception for isolate scopes (we won’t cover isolate scopes, but to learn more, check out our directives post where they are explained in great detail).

For example:

JS Bin

Summary: A controller is code that ties models to views using scopes

Learn more about controllers

Model-view-controller pattern

Angular supports the Model-View-Controller (aka MVC) software design pattern.

If you’re not familiar with MVC, the basic idea is that the model is the core data of our application (e.g. a car), the view is the user interface into our application (e.g. the page showing the car), and the controller is the code that ties the two together.

In our Angular code, the controller is responsible for updating the model. The controller can also talk to the view, but in Angular it does this through the $scope object.

The view is the interface the user sees and interacts with. In Angular the view is the HTML. As a user we only interact with the view and Angular manages how the view modifies the $scope.

Resources

$http, XHR, and Promises

Once we understand how to interact with data from within our own application, then the next logical step is to get data from the outside world and use it in our application.

How can we interact with back-end APIs with Angular?

Angular comes bundled with a wrapper around the XMLHttpRequest (also known as XHR, which is how you perform AJAX) called $http. The $http object is a library that helps you make HTTP requests and then parse the response. We often use $http

1
2
3
4
5
6
7
$http({ method: 'GET', url: 'http://foo.com/v1/api', params: { api_key: 'abc' } });

When this method runs, it will go and make a GET request to the back-end server at http://foo.com/v1/api with the parameter of api_key=abc.

XHR requests are asynchronous. This means that our application doesn’t have to pause our application and wait for a response from the server. The benefit is that the user can continue to use our application while the HTTP request is being made, but it introduces problems because once the data does come back from the server we have to deal with it. Because of this, asynchronous control flow it’s easy for our code to become cumbersome without the right tools.

In general, we have two options:

Promises

Promises are objects that help make working with async code feel like we’re writing synchronous code. Angular uses promises extensively, so it is important to get familiar with how to use them.

We use primarily only three methods when we use promises:

1
2
3
4
5
6
7
8
9
10
promise .then(function(data) { // Called when no errors have occurred with data }) .catch(function(err) { // Called when an error has occurred }) .finally(function(data) { // Called always, regardless of the output result })

When we have a promise object, we can depend upon the .then() method to get called when we have a non-failure response, the catch() method to get called when there is an error, and the finally() method to get called regardless of the result of the function.

The $http object returns a promise when it’s completed the XHR request. Now, to interact with our request, we’ll simply use the .then() function to load the data on our $scope:

1
2
3
4
5
6
7
8
9
10
11
12
13
var promise = $http({ method: 'GET', url: '/v1/api', params: { api_key: 'abc' } }); promise.then(function(obj) { // obj is the raw request object generated by Angular // and contains status codes, the raw data, headers, // and the config function used to make the request $scope.data = obj.data; });

Using $http

Now that we know how to use the $http object, we can interact with it in our controller like so:

1
2
3
4
5
6
7
8
9
10
11
12
angular.module('myApp', []) .controller('HomeController', function($scope, $http) { $http({ method: 'GET', url: '/v1/api', params: { api_key: 'abc' } }).then(function(obj) { $scope.data = obj.data; }); });

This is for demonstration purposes only. Don’t use the $http object inside a controller, instead implement it with a service. We’ll look at services shortly.

But wait… how did we get the $http object in the controller in the first place?

1
2
3
4
5
angular.module('myApp', []) .controller('HomeController', function($scope, $http) { // We have the $scope object and the $http object // available in here });

Learn more about Promises & XHR

Dependency Injection

Depdendency Injection (DI) is a term for how code gets a reference to it’s dependencies. Dependency injection, like use require in Node.js, require in Ruby, or import in Java refers to how objects get access to the dependencies they need to run properly. For instance, we’re not going to write the printf() function in C because we can us the libc library that has it implemented already. This libc library is considered a dependency.

The question is how do we get these dependencies we need to run our code?

As a project becomes more complex, we’ll need to organize our code into modules. Somewhere along the way we have to include those modules into our final code.

The situation is more complicated in client-side code because we’ll often load code from several different files. In the browser, when we’re loading several files from different locations at different times, they are returned in an unpredictable order. Without the right tools, managing this process can be a real pain.

Thankfully AngularJS takes care of this for us - dependency injection is the solution to these problems.

“Dependency injection” refers the process of us telling Angular what dependencies we need to use and Angular resolving dependencies when we need them.

For instance, in the following controller, we’ll want to get access to both the $scope object and the $q service. We’re telling (i.e. annotating) what we need to run our controller. Then, at runtime Angular will handle passing in (injecting) the dependencies for us.

1
2
3
4
5
angular.module('myApp', []) .controller('HomeController', function($scope, $q) { // We have the $scope object and the $q object // available in here });

We’ve asked Angular to inject in the $scope object several times previously in this article, but we never really explained what it meant. When we specify $scope as an argument to the controller function, we’re telling Angular to make the $scope object available for us to use. Specifying dependencies by using the arguments of a function is a common pattern in Angular.

Here are a few things we need to know about dependency injection:

Angular inspects the arguments to the function and infers that the variable “$scope” matches the $scope service. If we tried calling it $myScope, it won’t work.

If you want to depend on one of your custom modules from another custom module you use the setter syntax in the module function and supply requires in the second argument. Here’s an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
// say we have some services... angular.module('fullstack.services', []) // some code that defines services here .service('WeatherService', function() { // define the weather service here }); ); // and we want to use those services in our controllers angular.module('fullstack.controllers', ['fullstack.services']) // now we have WeatherService available );

The reason we can specify $scope and $q without specifying them as dependencies is because they are Angular built-ins so they’re already included.

We could specify, say

1
.controller('HomeController', function($scope, $q) {

or

1
.controller('HomeController', function($q, $scope) {

and either one will work.

If you try to, you’ll get an error.

This is a bit of an advanced tip, but we will share it anyway, because we want you to recognize it in case you run into it.

When it comes time to create a production application, it’s common to “minify” the javascript. This minification process changes variable names and it will break Angular’s ability to infer variable names.

There is an alternative syntax to deal with this referred to as the “inline annotation”. This is what it looks like:

1
2
3
.controller('HomeController', ['$scope', '$q', function($scope, $q) { // ... }]);

Looking at the example, we can see that instead of passing a function to controller, we’re passing an array. The arguments to this array are all names of modules we want to inject. The last argument is the function that defines the controller. The controller function then will be called with the injected modules in the same order.

This syntax is a little hairy, so in practice people use ng-min as a pre-compile step. ng-min turns the “inferring” syntax into the “inline annotation” to prep our code for minification.

Learn more about Dependency Injection

Services

Services are another core concept in AngularJS. When we used $http we were using an Angular service. Services are singleton objects that perform tasks common to several areas of the system.

1
2
3
4
5
6
7
angular.module('myApp.services', []) .service('WeatherService', function($http) { this.weatherFor = function(zip) { // do something with $http to get the weather here }; });

Then we could use our weather service in our controller:

1
2
3
4
angular.module('myApp.controllers') .controller('WeatherController', function($scope, WeatherService) { $scope.weather = WeatherService.weatherFor(90210); });

To reiterate: services are only created once. There is only a single instance of a given service in your application.

The idea here is that you want to keep your controllers thin. In the example above we technically could have written weatherFor in the controller directly, but by pulling it into a service we isolate responsibilities (e.g. each section of code does one thing). Also by having weatherFor in a service, that functionality is available to other controllers.

When we find our controllers getting bloated, it’s time to try to move code out of our controller and into a service. Not only is this good programming practice, it is easier to test services as a unit when they aren’t mixed up with the rest of our controller code.

*What’s the difference between a service, a factory, and a provider? As you read more Angular code you’ll see these three terms used almost interchangeably. That’s because *they’re all the same thing. service and factory are both implemented by provider under the hood. The difference is in the level of configuration you have when creating each one. For a concise example of the difference see here or here. For a longer detailed explaination, see here. But for now, just realize they’re the same thing under the hood.

Learn more about Angular services

Testing

One of the biggest benefits to using Angular is it’s designed to be testable from the ground-up. It strongly encourages functional separation between components, comes with testing integration. You can use Angular’s dependency injection and Angular’s testing suite works with the popular and powerful Jasmine framework.

Although we won’t cover how to test in this article (as there are plenty of fantastic resources listed in the resources section below), it’s a good idea to understand the different terminology to know how to get started.

When we build angular apps, there are two types of testing that we can do out of the box:

Unit testing

Unit testing is the process of testing small atomic units of functionality from the perspective of the code. With unit testing, we’ll create our angular objects ourselves, set up state and make assertions for how they should respond and interact with other components.

In unit testing, we are less concerned with the functionality of the application as a whole and more focused on how the individual objects interact with each other. For instance, we don’t care that the user clicks the login button and the login function runs, we will test only that the login function runs properly and how we expect.

An example unit test to test an Angular controller that has a single function that is responsible for showing a login page (for example) might look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
'use strict'; describe('Controller: HomeController', function () { // load the controller's module beforeEach(module('myApp')); var HomeCtrl, scope; // Initialize the controller and a mock scope beforeEach(inject(function($controller, $rootScope) { scope = $rootScope.$new(); HomeCtrl = $controller('HomeController', { $scope: scope }); })); it('should have a showLogin function', function () { expect(typeof(scope.showLogin)).toBe("function"); }); });

End-to-End testing (also known as E2E testing)

On the other hand, End-to-End testing doesn’t care how the login function works, just that it works as we expect it to work from the eyes of the user of the application. End-to-end testing allows us to pretend we are the user of the application and gives us the ability to define how a user interacts with the page in code. E2E testing frees us from needing to click around a page every time we make a change to ensure everything still works.

In E2E testing, we’re controlling a live browser, so our tests will reflect this. An example end-to-end test (using protractor) might look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
describe('page navigation', function() { var link; beforeEach(function() { link = element(by.css('.header ul li:nth-child(2)')); link.click(); }); it('should navigate to the /about page when clicking', function() { expect(browser.getCurrentUrl()).toMatch(/\/about/); }); it('should add the active class when at /about', function() { expect(link.getAttribute('class')).toMatch(/active/); }); });

Testing tools

Testing is the process of setting up expectations for the state and functionality of our code under different operating conditions. When we test, we’re focused on confirming that the running code is set as we expect it to be under conditions we defined.

JasmineJS

When testing our angular apps, we’ll use the JasmineJS testing framework to define our tests and expectations. Jasmine gives us a framework for writing behavior-driven testing which provides a descriptive set of functionality to define how our code should run. We’re given the describe() function to define the test suite, and expectations to provide the actual testing.

Karma

Karma is the testing environment we’ll use to set up a testing environment when developing angular apps. It is a test runner that will run our tests, provide our entire workflow (including live running of tests when files change), and allows us to write tests from different frameworks. It works nicely with continuous integration frameworks and allows us to debug our code right in the browser.

Protractor

The newest member of the core testing tools, Protractor is a testing framework built atop the production-ready WebDriverJS library which runs atop Selenium. It is fast and allows us to run against selenium clusters. Not only that, it provides a very clean interface to operate against the browser’s selenium service.

Resources

How to build an app

So there you have it - we’ve covered the major concepts of Angular. But you might be wondering, how do I actually build an app?

Here are two:

Tell us what you think

Have any questions about the content above? Was anything confusing? Enlightening? Leave a comment below!

Get the weekly email all focused on AngularJS. Sign up below to receive the weekly email and exclusive content.
We will never send you spam and it's a cinch to unsubscribe.

Download a free sample of the ng-book: The Complete Book on AngularJS

ng-book: The Complete Book on AngularJS is the canonical AngularJS book available today.

It's free, so just enter your email address and the PDF will be sent directly to your inbox. Mailchimp can take up to an hour to deliver the free sample chapter, but if you don't receive it within the hour, send us an email and we'll manually send them to you!

We'll send you updates about the book, when it updates and other free content.

We will never send you spam and it's a cinch to unsubscribe.

Comments

comments powered by Disqus