Angular Part 5–Adding A Service

image_thumb-1faf5ac22c21b6c1ba323ff00009c4343

This is the fifth in a series that starts here. In the previous installment, we looked at using Jasmine to test a Controller, and left off with the suggestion that our program would be improved by adding a service.  We’ll add that today.

Before we get to adding a service, however, it is time to make our application a bit more realistic by adding a couple views.  We’ll do that by adding an Admin and an Expense folder to our App folder. The former will hold views (html) and code (JavaScript) related to administering the application, while the latter will hold views and code relating to actual expenses,

image

 

  You can safely ignore the contents of expenseItem.js for now.  That is there as a place holder.

We’ll put some very simple HTML into the two HTML files.  Just a div or H1 with some text so we know when we are looking at that view.

We’ll come back and flesh these out later. For now, however, we need to set up our routes.  Under app add another JavaScript file named app.js

This file will contain the information Angular needs to navigate among the views.  It starts off by creating our module and stating that the module depends on ngRoute, which is the Angular library to support routing.

With that in place we can call config passing in an Angular $routeProvider object which we will use to manage our routing,

 

(function () {
‘use strict’;

// Create the module and define its dependencies.
var app = angular.module(‘app’, ['ngRoute']);

// config always runs before the services are ready.
app.config(['$routeProvider', function($routeProvider) {
$routeProvider
.when('/', { templateUrl: 'app/Expense/expense.html' })
.when('/admin', { templateUrl: 'app/Admin/admin.html' })
.otherwise({ redirectTo: '/' });
}
]);
})();

The config method always runs first, and here it is instructing Angular that the base directory should go to the expense.html file in the Expense directory, and the /admin path should go to Admin/admin.html.  All other addresses will redirect to the root and thus to expense.html.

Expense

Let’s move the display of the expenses to the expense.html file,

<h1>Expenses</h1>
<div ng-controller="expensesController as vm">

<table class="table table-bordered table-condensed" >
<thead>
<tr>
<th>Expense</th>
<th>Description</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="e in vm.expenseItems">
<td>{{e.type}}</td>
<td>{{e.description}}</td>
<td>{{e.amount | currency}}</td>
</tr>
</tbody>
</table>
</div>

 

Notice that the very first line declares our controller and names it vm. This allows us to refer to the controller as vm which reminds us it is acting as the view model.

We’ve seen the ng-repeat directive already.  Our controller is going to change a bit,however, as we’re going to move the data out of the controller and into a service.  Add a file under app named expensesDataService.js

The service begins by retrieving the module (app) and using it to create a factory.  The first argument to the factory method is the name of the new service, the second is an array of dependencies, ending with the service itself,

(function(){
‘use strict’

angular.module(‘app’)
.factory(‘expensesDataService’, ['$http',
expensesDataService]);

Next comes the function that creates the service, taking the dependency as a function argument.  I then create an object that exposes the public members of the service,

function expensesDataService($http){
var service = {
getExpenses: getExpenses,
persistExpenses : persistExpenses
};

return service;

Finally, all I need do is implement the methods I exposed,
function getExpenses(){
return [
new ExpenseItem('Taxi', 'To airport', 89.95),
new ExpenseItem('Dinner', 'At airport', 15.40),
new ExpenseItem('Coffee','Starbucks', 4.93)
] }

function reportExpenses(){
// some work
}

function persistExpenses(reportExpenses){
// do some work
var success = true;
if (success){
reportExpenses();
}
}
}
})();

 

You can see that I’ve stubbed out persistExpenses and its helper function reportExpenses.  The function getExpenses, however, provides then necessary service of returning an array of ExpenseItem objects.   Let’s define these objects in a file, expenseItem.js under the Expense directory:

function ExpenseItem(type, description, amount) {
this.type = type;
this.description = description;
this.amount = amount;
}

Notice that the implementing function in the service (expensesDataService) is an IIFE

The complete source code for today is located here.

The following two tabs change content below.

Jesse Liberty

Master Consultant at Falafel Software
Jesse Liberty is a Master Consultant for Falafel Software, an author and he creates courses for Pluralsight . He is a Microsoft MVP and a Certified Xamarin Mobile Developer. Liberty hosts the popular Yet Another Podcast and his blog is considered required reading. He was a Senior Evangelist for Microsoft, , a XAML Evangelist for Telerik , Distinguished Software Engineer at AT&T; Software Architect for PBS and Vice President of Information Technology at Citibank.