AngularJS: Introduction to Services
All AngularJS services are “singletons”, that is, there is only one instance of a specific service per Angular application to carry out some specific task.
Up until now, we have been working on the examples where all the data for the model has been included in the code. Although, this is fine for instructional purposes this is quite limiting in scope. Communicating with a server becomes essential in order to pull down data from files, databases, external systems via API calls, etc. AngularJS provides two services for this:
- $http: this service makes use of low-level HTTP calls via XMLHttpRequest or JSONP
- $resource: this service is dedicated to the REST API calls
Using services, allows developers a great way of separating logic from their controllers. AngularJS makes it very easy for developers to create their our own services for any complex operation.
In this tutorial, we will be specifically discussing the use of $http service to make AJAX and JSONP calls. In a subsequent post, I will discuss $resource, which, as stated above, is more appropriate for REST API calls.
1. AngularJS $http Service
The $http service provides a simple and elegant way to communicate with a web server using the HTTP protocol. I will mention, as a side bar, that our AJAX calls cannot be sent to a different domain from where the HTML page was loaded from without making some slight modifications on the server-side code.
This restriction on modern browsers was necessary to counter the security threat of cross-site scripting. However, with the explosion of AJAX and the rise of clients pulling data from various sources, many of which reside on different domains, changes have been coming at an astonishing pace.
Such “cross-domain” requests would otherwise be forbidden by web browsers, per the same origin security policy. CORS (Cross Origin Resource Sharing) defines a way in which the browser and the server can interact to determine whether or not to allow the cross-origin request.
Today, many of the modern browsers (Internet Explorer* 10+, Firefox 29+, Chrome 34+, Safari 6+ and Opera 21+) support CORS and can make requests to other domains so long as some provisions are made on the target server. I only mention this, because as you will see, I needed to make some changes to the header of the response object in my nodeJS application since it was technically running as a standalone web server (thereby using a different domain) then from the one hosting the AngularJS web application.
1.1 Let’s look at our sample application
Consider the typical scenario where we need to access some resource from a back-end data source. In our example, I have a web server running Apache Tomcat which is hosting the application on my localhost at port 7777. I then created a simple nodeJS web application running on port 8888 (this is cross domain) to pull in data from an array. In this first example, I decided not to pull from any additional external data source, but in subsequent examples, we will pull data from files and then from mongoDB database.
Take a few minutes and spend some time reviewing what a typical scenario would look like using the diagram I have provided.
1.2 Internal Services
AngularJS provides many internal services that we can use in our applications. These are just some of them: $animate, $location, $log, $window, $httpBackend and $route. For a complete list of services provided by AngularJS I would recommend reviewing the Angular API Reference.
1.3 The Javascript
(function() {var app = angular.module("app", []); app.controller("HttpCtrl", function($http) { var app = this; var response = $http.get("http://localhost:8888/"); response.success(function(data) { app.books = data; }) response.error(function(data, status, headers, config) { alert("AJAX failed to get data, status=" + status); }) }); })();
1.4 The HTML
<!DOCTYPE html> <html ng-app="app"> <head> <title>Angular Simple Service</title> <link rel="stylesheet" type="text/css" href="include/styles.css"> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.1/angular.min.js"> </script> <script type="text/javascript" src="include/app2.js"> </head> <body> </script> <div ng-controller="HttpCtrl as app" > <table class="striped"> <tr> <th>Title</th> <th>Author</th> <th>Price</th> <th>ISBN</th> </tr> <tr ng-repeat="book in app.books"> <td>{{ book.title }}</td> <td align="center">{{ book.author }}</td> <td align="right">{{ book.price | currency}}</td> <td align="center">{{ book.isbn }}</td> </tr> </table> </div> </body> </html>
1.5 NodeJS Server
/* Using Node.js to create a version simple HTTP server that will output JSON data back to the user. To make things simple I have created a JSON book object that will be used. */ var http = require("http"); var data = [ { title: "Charlotte's Web", "price": 6.35, "isbn": "978-0739477076", author: "E. B. White"}, { title: "Great Expectations", "price": 2.87, "isbn": "978-0486415864", "author": "Charles Dickens"}, { title: "Harry Potter and the Sorcerers Stone", "price": 6.92, "isbn": "978-0590353427", "author": "J.K. Rowling"}, { title: "Beloved", "price": 8.75, "isbn": "978-1400033416", "author": "Toni Morrison" }, { title: "Moneyball: The Art of Winning an Unfair Game", "price": 9.01, "isbn": "978-0393324815", "author": "Michael Lewis"}, ]; var responseString = JSON.stringify(data); var host = '127.0.0.1'; var port = 8888; console.log("Data available on server: " + responseString); console.log("Starting http server..."); /* Simple HTTP server using NodeJS, support for CORS required, otherwise, Mozilla and Chrome browsers reject responses notice some access-controls-allow-* added to header */ var headers = { 'Content-type':'application/json', 'Content-Length': responseString.length, 'Access-Control-Allow-Origin' : '*', 'Access-Control-Allow-Methods': 'POST, GET, OPTIONS', 'Access-Control-Allow-Headers': 'X-Requested-With, content-type' }; var server = http.createServer(function(req, res) { console.log("Received request " + req.url); res.writeHead(200, headers); res.end(responseString); }); server.listen(port, host, function() { console.log("Listening on " + host + ":" + port); });
2. Connecting to MongoDB Database
For this next example, we will connect to a mongoDB database. I am using MongoLab (MongoDB-as-a-Service), which allows us to quickly create a database and give us easy accessibility from a web server using the REST API.
For this example, I inserted the following documents into the collection.
MongoLab provides a very simple and elegant way to access your mongoDB database using the following REST API syntax:
Using my APIKey, click the link to see the raw JSON data from mongoDB
2.1 Using CURL
cURL is a command line tool for getting or sending files using URL syntax.
Since cURL uses libcurl, it supports a range of common Internet protocols, currently including HTTP, HTTPS, FTP, FTPS, SCP, SFTP, TFTP, LDAP, LDAPS, DICT, TELNET, FILE, IMAP, POP3, SMTP and RTSP. On a Unix or Linux system using cURL:
cURL Output
HTTP/1.1 200 OK Date: Sun, 9 Feb 2014 23:20:45 GMT Server: Apache/2.2.22 (Ubuntu) Expires: Tue, 01 Feb 2000 08:00:00 GMT Last-Modified: Sun, 9 Feb 2014 23:20:45 GMT Cache-Control: no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0 Pragma: no-cache X-Frame-Options: DENY Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: * Connection: close Transfer-Encoding: chunked Content-Type: application/json;charset=utf-8 [ { "_id" : { "$oid" : "5429c1b0e4b0142af66429b8"} , "title" : "Charlotte's Web" , "price" : 6.35 , "isbn" : " 978-0739477076" , "author" : "E. B. White"} , { "_id" : { "$oid" : "5429c211e4b0142af66429b9"} , "title" : "Gr eat Expectations" , "price" : 2.87 , "isbn" : "978-0486415864" , "author" : "Charles Dickens"} , { "_id" : { " $oid" : "5429c2a3e4b0142af66429bf"} , "title" : "Moneyball: The Art of Winning an Unfair Game" , "price" : 9.0 1 , "isbn" : "978-0393324815" , "author" : "Michael Lewis"} , { "_id" : { "$oid" : "5429cb55e4b0142af6642a18"} , "title" : "Black Beauty" , "price" : 4.05 , "isbn" : "978-0486407883" , "author" : "Anna Sewell"} , { "_id" : { "$oid" : "5429cbbde4b0142af6642a22"} , "title" : "Diary of a Wimpy Kid" , "price" : 7.88 , "isbn" : "978- 0810993136" , "author" : "Jeff Kinney"} , { "_id" : { "$oid" : "5429cc13e4b0142af6642a26"} , "title" : "The Bo rrowers" , "price" : 3.94 , "isbn" : "978-0152047375" , "author" : "Mary Norton"} , { "_id" : { "$oid" : "5429 cc9de4b0142af6642a2d"} , "title" : "Among the Hidden" , "price" : 4.99 , "isbn" : "978-0689824753" , "author" : "Margaret Peterson Haddix"} ]
2.3 The Javascript
var app = angular.module("app", []); app.controller("HttpCtrl", function($http) { var app = this; var response = $http.get("https://api.mongolab.com/api/1/databases/library/collections/books?apiKey=Bfl0MpDXd9_HMSv754M_y6shYqYtUPp2"); response.success(function(data, status, headers, config) { app.books = data; }) response.error(function(data, status, headers, config) { alert("AJAX failed to get data, status=" + status); }) });
2.4 Output
3. What’s Next
From here, we will go on to continue to work with AngularJS services. This time, we will create our own services and show you the different ways you can use custom services.
Leave a Reply