In this example you will build an intermediate database access service that uses the $http
service to connect to a simple Node.js server that will act as a server-side database service. The purpose of this exercise is to illustrate the usage of built-in services alongside custom services. This also gives a good example of utilizing the $q
service.
Listing 10.5 implements the Node.js web server that handles the following GET
and POST
routes to get and set a user object and an array of table data to simulate making requests to a remote database service:
■ /get/user: A GET
route that returns the JSON version of a user object.
■ /get/data: A GET
route that returns the JSON version of an array of table data.
■ /set/user: A POST
route that accepts a user object in the body of the request and updates the object on the server to simulate storing a user object.
■ /set/data: A POST
route that accepts an array of objects in the body of the request and updates the data variable to simulate storing database data. Typically, you would never store all the table data at once but for simplicity of this example this is how it is.
You don’t necessarily need to pay a lot of attention to the code in Listing 10.5 other than understanding the routes that it provides so that you can follow the interactions in the AngularJS application defined in Listings 10.6, 10.7, and 10.8. The server is very rudimentary, doesn’t handle errors, and just dynamically generates data to simulate the database.
Note
You will need to stop the normal server.js
HTTP server if it is running before starting service_server.js
from Listing 10.5. Also, you will want to place the service_db_server.js
file from Listing 10.5 in the parent folder to the service_db_access.html
in Listing 10.6 for the paths to match up properly in the Node.js static routes. The structure should look similar to this:
./service_db_server.js
./ch10/service_custom_db.html
./ch09/js/service_custom_db_access.js
./ch09/js/service_custom_db.js
01 var express = require('express'),
02 var bodyParser = require('body-parser'),
03 var app = express();
04 app.use('/', express.static('./'));
05 app.use(bodyParser.urlencoded({ extended: true }));
06 app.use(bodyParser.json());
07 var user = {
08 first: 'Christopher',
09 last: 'Columbus',
10 username: 'cc1492',
11 title: 'Admiral',
12 home: 'Genoa'
13 };
14 var data = [];
15 function r(min, max){
16 var n = Math.floor(Math.random() * (max - min + 1)) + min;
17 if (n<10){ return '0' + n; }
18 else { return n; }
19 }
20 function p(start, end, total, current){
21 return Math.floor((end-start)*(current/total)) + start;
22 }
23 function d(plusDays){
24 var start = new Date(1492, 7, 3);
25 var current = new Date(1492, 7, 3);
26 current.setDate(start.getDate()+plusDays);
27 return current.toDateString();
28 }
29 function makeData(){
30 var t = 70;
31 for (var x=0; x < t; x++){
32 var entry = {
33 day: d(x),
34 time: r(0, 23) + ':' + r(0, 59),
35 longitude: p(37, 25, t, x) + 'u00B0 '+ r(0,59) + ' N',
36 latitude: p(6, 77, t, x) + 'u00B0 '+ r(0,59) + ' W'
37 };
38 data.push(entry);
39 }
40 }
41 makeData();
42 app.get('/get/user', function(req, res){
43 res.json(user);
44 });
45 app.get('/get/data', function(req, res){
46 res.json(data);
47 });
48 app.post('/set/user', function(req, res){
49 console.log(req.body.userData);
50 user = req.body.userData;
51 res.json({ data: user, status: "User Updated." });
52 });
53 app.post('/set/data', function(req, res){
54 data = req.body.data;
55 res.json({ data: data, status: "Data Updated." });
56 });
57 app.listen(80);
The code in Listing 10.6 implements a module named dbAccess
and a custom service named DBService
. The DBAccessObj()
function that creates the service object provides the getUserData()
and updateUser()
methods to retrieve and update the user object from the server using $http
requests. The getData
and updateData()
methods provide similar functionality for the table data. Notice how the $q
service is used to defer the response to the $http
requests since the request will not return immediately.
The code in Listing 10.7 implements the application module. Notice that on line 1 the dbAccess
module is injected into the myApp
module to provide access to the DBService
service. DBService
is injected into the controller on line 2 and then used on lines 6, 12, 18, and 23 to make calls to get and set data from the server and assign it to the $scope.userInfo
and $scope.data
values in the scope. Notice how the $q
service then()
function is used to handle the deferred responses. For simplicity only the successCallback
function is implemented. Normally you would also want to implement an errorCallback
function as well.
The code in Listing 10.8 implements an AngularJS template that displays the user info in text inputs and binds the values directly to the scope. There are also two input buttons that call updateUser()
to update the user info on the server and getUser()
to refresh the scope data from the server. Similarly, there are two input buttons that call updateData()
and getData()
to provide the same functionality for updating and refreshing the table data from the model.
Figure 10.3 shows the rendered AngularJS web application working. When you click on the Update User or Update Data buttons, the values are changed on the server. That means that you can reload the web page and even exit the browser and come back, and the values will still be the updated versions.
01 var app = angular.module('dbAccess', []);
02 function DBAccessObj($http, $q) {
03 this.getUserData = function(){
04 var deferred = $q.defer();
05 $http.get('/get/user')
06 .success(function(response, status, headers, config) {
07 deferred.resolve(response);
08 });
09 return deferred.promise;
10 };
11 this.updateUser = function(userInfo){
12 var deferred = $q.defer();
13 $http.post('/set/user', { userData: userInfo}).
14 success(function(response, status, headers, config) {
15 deferred.resolve(response);
16 });
17 return deferred.promise;
18 };
19 this.getData = function(){
20 var deferred = $q.defer();
21 $http.get('/get/data')
22 .success(function(response, status, headers, config) {
23 deferred.resolve(response);
24 });
25 return deferred.promise;
26 };
27 this.updateData = function(data){
28 var deferred = $q.defer();
29 $http.post('/set/data', { data: data}).
30 success(function(response, status, headers, config) {
31 deferred.resolve(response);
32 });
33 return deferred.promise;
34 };
35 }
36 app.service('DBService', ['$http', '$q', DBAccessObj]);
01 var app = angular.module('myApp', ['dbAccess']);
02 app.controller('myController', ['$scope', 'DBService',
03 function($scope, db) {
04 $scope.status = "";
05 $scope.getUser = function(){
06 db.getUserData().then(function(response){
07 $scope.userInfo = response;
08 $scope.status = "User Data Retrieve.";
09 });
10 };
11 $scope.getData = function(){
12 db.getData().then(function(response){
13 $scope.data = response;
14 $scope.status = "User Data Retrieve.";
15 });
16 };
17 $scope.updateUser = function(){
18 db.updateUser($scope.userInfo).then(function(response){
19 $scope.status = response.status;
20 });
21 };
22 $scope.updateData = function(){
23 db.updateData($scope.data).then(function(response){
24 $scope.status = response.status;
25 });
26 };
27 $scope.getUser();
28 $scope.getData();
29 }]);
01 <!doctype html>
02 <html ng-app="myApp">
03 <head>
04 <title>AngularJS Custom Database Service</title>
05 <style>
06 label {
07 display: inline-block; width: 75px; text-align: right; }
08 td, tr {
09 width: 125px; text-align: right; }
10 p {
11 color: red; font: italic 12px/14px; margin: 0px;}
12 h3 {
13 margin: 5px; }
14 </style>
15 </head>
16 <body>
17 <h2>Custom Database Service:</h2>
18 <div ng-controller="myController">
19 <h3>User Info:</h3>
20 <label>First:</label>
21 <input type="text" ng-model="userInfo.first" /><br>
22 <label>Last:</label>
23 <input type="text" ng-model="userInfo.last" /><br>
24 <label>Username:</label>
25 <input type="text" ng-model="userInfo.username" /><br>
26 <label>Title:</label>
27 <input type="text" ng-model="userInfo.title" /><br>
28 <label>Home:</label>
29 <input type="text" ng-model="userInfo.home" /><br>
30 <input type= button ng-click="updateUser()" value="Update User" />
31 <input type= button ng-click="getUser()" value="Refresh User Info" />
32 <hr>
33 <p>{{status}}</p>
34 <hr>
35 <h3>Data:</h3>
36 <input type= button ng-click="updateData()" value="Update Data" />
37 <input type= button ng-click="getData()" value="Refresh Data Table" /><br>
38 <table>
39 <tr><th>Day</th><th>Time</th><th>Latitude</th><th>Longitude</th></tr>
40 <tr ng-repeat="datum in data">
41 <th>{{datum.day}}</th>
42 <td><input type="text" ng-model="datum.time" /></td>
43 <td><input type="text" ng-model="datum.latitude" /></td>
44 <td><input type="text" ng-model="datum.longitude" /></td>
45 </tr>
46 </table>
47 <hr>
48 </div>
49 <script src="http://code.angularjs.org/1.3.0/angular.min.js"></script>
50 <script src="js/service_custom_db_access.js"></script>
51 <script src="js/service_custom_db.js"></script>
52 </body>
53 </html>