Angular Basics
Angular is a JavaScript framework for building Single Page Applications (SPA). There are a few key concepts required to work with Angular including dependency injection, controllers, services, and directives. In the following sections I will provide an introduction to these concepts and some simple examples of each concepts creation and use.
Before we can get started, we need to download, link to, or otherwise reference angular in our we application. To do so, use one of the following methods:
-
npm install angular
-
bower install angular
- download angular from Angular’s Website
- use a cdn ex.
Dependency Injection
Angular’s dependency injection is at the heart of operation. Without correctly configuring and using the dependency injection, nothing in Angular will work.
'use strict'; // Declare app level module which depends on views, and components angular.module('myApp', [ 'ngRoute', 'myApp.view1', 'myApp.view2', 'myApp.version' ]). config(['$routeProvider', function($routeProvider) { $routeProvider.otherwise({redirectTo: '/view1'}); }]);
In the above, “angular.module” is used to define the “myApp” module in Angular’s dependency system. The module has dependencies on “ngRoute”, “myApp.view1”, “myApp.view2”, etc. At the close of the module function, a “config” function is called. In the config function we are setting up routing. In order to configure routing we need Angular’s routeProvider. In Angular when a dependency in required, generally, we will use an array to define the dependency requirements with the last element in the array being the function that uses the dependencies.
Controllers
A controller in Angular is used to manage the business logic interactions for a defined section of a page. For the example app a controller is equivalent to a page.
'use strict'; var application = application || {}; (function(ns) { ns.View1Controller = function(sample) { var vm = this; vm.letter = sample.getData()[1]; console.log(vm.letter); }; })(application);
'use strict'; var application = application || {}; (function(ns) { angular.module('myApp.view1', ['ngRoute']) .config(['$routeProvider', function($routeProvider) { $routeProvider.when('/view1', { templateUrl: 'view1/view1.template.html', controller: 'View1Ctrl', controllerAs: 'vm' }); }]) .controller('View1Ctrl', ['Sample', ns.View1Controller]); })(application);
This is the partial for view 1.
A letter: {{vm.letter}}
In the above snippets, I have broken the controllers full definition out into 3 files. The controller file defines the business logic devoid of anything related to angular. I like to do this because I feel it aids in testing my logic without attaching my code to a framework. Doing things this way I can, with relative ease, switch frameworks or pieces of a framework at a later date.
Notice that the controller function is wrapped in an Immediately Invoked Function Expression (IIFE). This provides our code with isolation and protection from other libraries. The only way another library could accidentally overwrite our logic is if the other library also used the “application” namespace.
The config file is where angular steps in. We first define a module for view1. The view1 module requires ngRoute and uses the route provider very similarly to the core app module. Here we set the html template to use for this route, and the controller to use.
Now that the route is configured, we configure a controller. Using the controller function in the angular namespace we set “View1Ctrl” as the controllers name and just as before we configure the dependencies for our controller. Here the dependency is a service named Sample
Services
In Angular a service is usually used to gather data from the web server. Services are singletons within the system so they can also be used as a type of caching mechanism when the need arises.
'use strict'; var application = application || {}; (function(ns) { ns.SampleService = function() { var self = this; console.log('test'); self.data = ['A', 'B', 'C']; self.getData = function() { return self.data; }; }; })(application);
/* globals angular */ 'use strict'; var application = application || {}; (function(ns) { angular.module('myApp.view1') .service('Sample', [ns.SampleService]); })(application);
As you can see, other than the singleton nature of a service there really isn’t much difference from a controller. The biggest difference is the usage. A controller is used to manipulate the values and behavior displayed to the user of the application, whereas a service is used by the controllers to manipulate data on a server.
Directives
This is where Angular gets “hard”. Directives are used to create web components that can be used over and over again. Directives are also used to break an application page into logically organized pieces. Many believe that directives are the hardest part of working with angular. They do have a lot of caveats but can be created and used with relative ease once you realize the danger areas that will send you down a rabbit hole.
'use strict'; var application = application || {}; (function(ns) { ns.VersionController = function(version, element) { element[0].innerText = version; }; })(application);
/* globals angular */ 'use strict'; var application = application || {}; (function(ns) { angular.module('myApp.version.version-directive', []).directive('appVersion', function(version) { return { restrict: 'A', controller: ['version', '$element', ns.VersionController] }; }); })(application);
My AngularJS App
The above example is a simple example of an attribute directive. Attribute directives are added as attributes to elements and will perform an action, usually some type of DOM manipulation. You can see the directive in use on line 29 of index.html above.
I don’t have an example here, but there are also Element directives which are use as actual html elements.
The main difference with element directives would be setting the restrict to ‘E’ instead. You can also allow multiple usage types, ‘EA’ for example.
The trouble with directives starts when you want to pass something down to a directive by using it’s attributes. To do this you must add scope to the directive and you may only have one privately scoped directive in a hierarchy. So you cannot have a privately scoped directive inside another privately scoped directive. We will get into how to do this some other time.
Enough to get started
I hope this has been enough to get started. If you need more or something is unclear please leave a comment and I will do my best to either update this post or create a new post to cover the question.
Clayton has been programming professionally since 2005 doing mostly web development with an emphasis on JavaScript and C#. He has a focus Software Craftsmanship and is a signatory of both the Agile Manifesto and the Software Craftsmanship manifesto. He believes that through short iterations and the careful gathering of requirements that we can deliver the highest quality and the most value in the shortest time. He enjoys learning and encouraging other to continuously improve themselves.