Consuming data with AngularJS

We often want to display data coming from sources like our databases, but also we can do it sending requests to web services that are out of range of our network to get that data. In our example, we’ll use data stored in Google’s servers using the Book API that returns data in JSON format.

Here’s the final result:

angularjs_consuming_data_fr

First, we have to define the place in the application where data will be displayed. Here we’ll use AngularJS UI Router.

...
	<div class="container">
		<header ng-include="'views/header.html'" class="header"></header>
		<br />
		<div ui-view="viewMain"></div>
		<div ui-view="viewSearch"></div>
		<div ui-view></div>
		<p>&nbsp;</p><p>&nbsp;</p>
		<div ui-view="viewSubjectsNavBar"></div>
		<footer ng-include="'views/footer.html'"></footer>
	</div>

...
 

But, where’s the viewSearch view?

It is part of views element of home state. States are defined implementing the $stateProvider service in order to manage them.

...

angular.module('myLibraryApp')
	.config(function ($stateProvider, $urlRouterProvider){
		$stateProvider
			/*
			 * HOME
			 */
			.state('home', {
				url: '/',
				views: {
					// jumbotron info
					'viewMain': { 
						templateUrl: 'views/main.html' 
					},
					// search bar
					'viewSearch': { 
						templateUrl: 'views/search.html', 
						controller: 'SearchController' 
					},
					// subjects navigation bar
					'viewSubjectsNavBar': { 
						templateUrl: '/subjects/subjects.NavBar.html',
						controller: 'SubjectsListController'
					}
				}
			})

...
 

So, in our search.html file, we can find the template used to print books information in the results list. To do this, we can use the ng-repeat directive.

<div ng-controller="SearchController" class="form-group" width="90%">
	<form id="frmSearch" name="frmSearch" role="form">
		<p>Tape a title or subject and then choose one book from the results list.</p>
		<table align="center">
			<tr>
				<td>
					<input id="txtSearch" placeholder="Type a title or subject..." class="form-control" ng-model="txtSearch" ng-change="onTextChange()" />
				</td>
			</tr>
			<tr>
				<td id="searchResultsList">
					<table class="table {{ (booksList == undefined) ? 'hidden' : 'show' }}">
						<tr ng-repeat="book in booksList.items">
							<td valign="top">
								<a ui-sref="documents.detail({ id: book.id })" ui-sref-active="active" name="doc_{{ book.id }}">
									<img src="{{ book.volumeInfo.imageLinks.smallThumbnail }}" border="0" alt="">
								</a>
							</td>
							<td>
								<a ui-sref="documents.detail({ id: book.id })" ui-sref-active="active" name="doc_{{ book.id }}">
									<strong>Title</strong>: {{ book.volumeInfo.title }} 
								</a>
								<br />
								<strong>Subtitle</strong>: {{ book.volumeInfo.subtitle }} 
								<br />
								<strong>Authors</strong>: 
								<br />
								<div id="authors" ng-repeat="author in book.volumeInfo.authors">
									{{ author }}, <br />
								</div>
							</td>
						</tr>
					</table>
				</td>
			</tr>
		</table>
	</form>
	<p>&nbsp;</p>
</div>
 

Finally, magic happens into the onTextChange method. Note that we define a request variable with the Google’s Book API URL that will be sent as parameter of http.get method. If there’s a response, it will set the response to the booksList scope variable.

angular.module('myLibraryApp')
	.controller('SearchController', function ($scope, $http){
		// search box to query Google Books API
		$scope.onTextChange = function (){
			// Start timing now
			console.time('SearchController.onTextChange.job.timespan');

			//count character of text box
			if ($scope.txtSearch.length > 4){
				//log
				console.log( 'Searching for: '+ $scope.txtSearch );
				
				//do search
				var request = 'https://www.googleapis.com/books/v1/volumes?q=' + $scope.txtSearch.replace(' ', '+');
				
				//get query results using $http 
				$http.get(request)
				.success(function (response){
					$scope.booksList = response;
				})
				.error(function (err){
					//error log
					console.log('SearchController.onTextChange.error: '+ new Date().toLocaleTimeString() +' '+ $scope);
					
					// return
					$scope.searchResults = JSON.stringify(err);
				});
			}

			// Stop timer.
			console.timeEnd('SearchController.onTextChange.job.timespan');
		};
	});
 

Related Links

https://docs.angularjs.org/api/ng/service/$http

https://docs.angularjs.org/guide/scope

http://angular-ui.github.io/ui-router/site/#/api/ui.router

https://developers.google.com/books/

Leave a comment