AngularJS is a Javascript MVC framework from the fine folks over at Google. The focus of Angular is building complex HTML based client applications. Its design philosophy is data first, where your data will be updating the DOM. Contrast this to a framework like JQuery where the DOM will update your data.

AngularJS Logo

This is the eight in a series of posts on AngularJS where we are using Chemistry data from the periodic table to help us understand the framework. The others posts are

  1. AngularJS - Introduction
  2. AngularJS - Introducing AngularJS Controllers
  3. AngularJS - Introducing NG-Repeat
  4. AngularJS - More with NG-Repeat
  5. AngularJS - Image Binding
  6. AngularJS - Introducing Templates
  7. AngularJS - Introducing Routing
  8. AngularJS - Introduction to Services
  9. AngularJS - Introduction to Directives

Note: AngularJS does not allow for more than one ng-app directive. When I have multiple angular posts on the home page of my blog, only one application will work. I need to refactor the entire site to account for this. All of that to say this, you are best clicking on a single article so you can see the pages in action.

In AngularJS, when we want to create common code to be shared across our application, we create services. In the Angular world, the controller is the traffic cop, which directs data to your view for binding. Logic for retrieving that data falls to a service.

Services are stateless object that have shared functions that can be used in multiple controllers or views. The functions on services are also available throughout; they can be accessed in directives, controllers, filters, etc.

For an example of a real world service that I have used in the past…. When creating a select list in HTML for an AngularJS application, you usually have an ID associated with a selected element from the list. Often you will display all the properties of the JSON object. In JavaScript, to find this element, you need to loop through all the elements in an array until you get a match on the key. Depending on the size of your application, you end up writing this logic many, many times. To minimize this, I have written a helper application that creates an array that allows for an element to be accessed by a key value, thus reducing the need for repetitive array looping.

Generally, there are two ways to create services within your application. The most common is to use module.service within your application. The second is module.factory. There are a couple of other ways, but we will skip those. AngularJS services are really singleton objects. The object from services are then available across your application via dependency injection, which we will look at soon.

The main difference between the two service creation methods is how they are used. The module.service approach creates an instance of a function. A good use case for this approach is the generic array lookup function mentioned above. The module.factory approach is that the returned value is returned by invoking a function reference. This essentially allows you to treat the service like a class that you can new to make new instances.

The syntax for module.service is

var chemistryApp = angular.module('chemistryApp', []);

//
chemistryApp.service('chemistryService', function(){
    this.elementName= function(element){
        return element.name;
    };
});

//
function ChemCtrl($scope, chemistryService)
{
    ...
    $scope.nameFromService = chemistryService.elementName(elements[0]);
}

The syntax for module.factory is

var chemistryApp = angular.module('chemistryApp', []);

//
chemistryApp.factory('chemistryService', function(){
      return {
            nameFromService: function(element){
               return element.name;
            }
        }
    });

//
function ChemCtrl($scope, chemistryService)
{
    ...
    $scope.nameFromFactory = chemistryService.elementName(elements[0]);
}

Once we create our service, we want to be able to use this within our application. This is done via the magical gremlins that drive the Dependency Injection model in AngularJS. We just pass the service name to our controller when we instantiate it. We showed this above, but just to be sure, by passing chemistryService to the controller, it is service is available within the controller scope

function ChemCtrl($scope, chemistryService)
{
    ...
    $scope.nameFromFactory = chemistryService.elementName(elements[0]);
}

Let's look at a more advanced scenario. I am pretty much stealing this demo from my Skyline Technologies colleague Brian Mahloch. Brian came up with a great demo for demonstrating services using the Periodic Data, which he kindly let me steal.

What we are going to do is determine the type of bonds two elements would make, based on the differences in their electronegativity. We will create a service that does two things, calculate the differences in electronegativty and then based on the difference determine the type of bond.

Our service then looks like

chemistryApp.service('chemistryService', function () {

    this.calculateElectronegativityDifference = function (element1, element2) {

        return Math.abs(element1.electronegativity - element2.electronegativity);

    };

    this.convertElectronegativityDifferenceToName = function (difference) {

        if (difference > 2.0) {
            return 'Ionic Bond';
        } else if (difference >= 0.5 < 1.6) {
            return 'Polar Covalent Bond';
        } else {
            return 'NonPolar Covalent Bond';
        }

    };
});

Our controller creation then gets updated so that we are injecting the service into the parameter list. Next, since $scope is our conduit for the view to talk to the service, we create a function on the controller that will consume the service when we have two elements selected.

chemistryApp.controller('chemServiceCtrl', ['$scope', 'chemistryService',
    function chemServiceCtrl($scope, $log, chemistryService) {

        $scope.elements = periodicData.elements;

        $scope.calculateBondPolarity = function () {

            if ($scope.selectedElement1 && $scope.selectedElement2) {

                $scope.currentBondDifference = chemistryService.calculateElectronegativityDifference($scope.selectedElement1, $scope.selectedElement2);
                $scope.currentBondType = chemistryService.convertElectronegativityDifferenceToName($scope.currentBondDifference);

            }

        };

        /* private methods */

    }]
);

Tying it all together, we have something like this.

Element 1:
Element 2:
You have selected:
{{selectedElement1.name}}
Electronegativity:
{{selectedElement1.electronegativity}}
You have selected:
{{selectedElement2.name}}
Electronegativity:
{{selectedElement2.electronegativity}}
{{selectedElement1.name}} + {{selectedElement2.name}} = {{currentBondType}}

With a electronegativity difference of {{currentBondDifference | number:2}} {{selectedElement1.name}} and {{selectedElement2.name}} would form a {{currentBondType}}

We can now start to see how AngularJS provides a platform for creating web applications. With services, we are able to encapsulate logic and use it within multiple controllers in our application.

You can either visit http://angularperiodic.azurewebsites.net/ to see the code in action and as always find the code out on GitHub.