AngularJS components
AngularJS is driven from HTML, unlike most client-side JavaScript frameworks. In a typical web page, AngularJS takes care of wiring key pieces of code for you. So, if you add a bunch of AngularJS directives to your HTML page and include the AngularJS source file, you could easily build a simple app without writing a single line of JavaScript code.
To illustrate the preceding statement, we can build a login form with validations, without writing a single line of JavaScript.
It would look something like this:
<html ng-app=""> <head> <script src="angular.min.js" type="text/JavaScript"></script> </head> <body> <h1>Login Form</h1> <form name="form" method="POST" action="/authenticate"> <label>Email Address</label> <input type="email" name="email" ng-model="email" required> <label>Password</label> <input type="password" name="password" ng-model="password" required> <input type="submit" ng-disabled="!email || !password" value="Login"> </form> </body> </html>
In the preceding code snippet, the attributes that start with ng-
are called as AngularJS directives.
Here, the ng-disabled
directive takes care of adding the disabled attribute to the Submit button when the e-mail or password is not valid.
Also, it is safe to say that the scope of the directive is limited to the element and its children on which the directive is declared. This solves another key issue with the JavaScript language where, if a variable were not declared properly, it would end up in the Global Object, that is, the Window Object.
Note
If you are new to scope, I recommend that you go through https://docs.angularJS.org/guide/scope. Without proper knowledge of scope and root scope, this book would be very difficult to follow.
Now, we will go to the next component of AngularJS named Dependency Injection (DI). DI takes care of injecting units of code where required. It is one of the key enablers that help us achieve separation of concerns.
You can inject various AngularJS components, as you require. For instance, you can inject a service in a controller.
Note
DI is another core component of AngularJS that you need to be aware of. You can find more information at https://docs.angularJS.org/guide/di.
To understand services and controllers, we need to take a step back. In a typical client-side MVC framework, we know that the model stores the data, the view displays the data, and the controller massages the data present in the model before it gets displayed to the view.
In AngularJS, you can relate with the preceding line as follows:
- HTML—Views
- AngularJS controllers—Controllers
- Scope objects—Model
In AngularJS, HTML acts as the templating medium. An AngularJS controller would take the data from scope objects or the response from a service and then fuse them to form the final view that gets displayed on the web page. This is analogous to the task we did in the search example where we iterated over the results, built the HTML string, and then injected the HTML into the DOM.
Here, as you can see, we are separating the functionality into different components.
To reiterate, the HTML page acts as a template, and the factory component is responsible for making an AJAX request. Finally, the controller takes care of passing on the response from factory to the view, where the actual UI is generated.
The AngularJS version of the search engine example would be as shown here.
The index.html
or the main page of the app would look like this:
<html ng-app="searchApp"> <head> <script src="angular.min.js" type="text/JavaScript"> <script src="app.js" type="text/JavaScript"> </head> <body ng-controller="AppCtrl"> <h1>Search Page</h1> <form> <label>Search : </label> <input type="text" name="query" ng-model="query" required> <input type="button" ng-disabled="!query" value="Search" ng-click="search()"> </form> <p ng-repeat="res in results"> <h2>{{res.heading}}</h2> <span>{{res.summary}}</span> <a ng-href="{{res.link}}">{{res.linkText}}</a> </p> </body> </html>
The app.js
would look like this:
var searchApp = angular.module('searchApp', []); searchApp.factory('ResultsFactory', ['$http', function($http) { return { getResults : function(query){ return $http.post('/getResults', query); } }; }]); searchApp.controller('AppCtrl', ['$scope','ResultsFactory',function($scope, ResultsFactory) { $scope.query = ''; $scope.results = []; $scope.search = function(){ var q = { query : $scope.query }; ResultsFactory.getResults(q) .then(function(response){ $scope.results = response.data.results; }); } }]);
Note
In AngularJS, the factory component and the service component are interchangeably used. If you would like to know more about them, refer to the discussion on stack overflow at http://stackoverflow.com/questions/15666048/service-vs-provider-vs-factory.
The index.html
file consists of the HTML template. This template is hidden by default when the page is loaded. When the results array is populated with data, the markup is generated from the template using the ng-repeat
directive.
In app.js
, we started off by creating a new AngularJS module with the name as searchApp
. Then, we created a factory named ResultsFactory
, whose sole purpose is to make an AJAX call and return a promise. Finally, we created the controller, named AppCtrl
, to coordinate with the factory and update the view.
Note
If you are new to promises, refer to http://www.dwmkerr.com/promises-in-angularJS-the-definitive-guide/.
The search
function declared on the button's ng-click
directive is set up in the AppCtrl
. This button would only be enabled if valid data is entered in the search box. When the Search button is clicked, the listener registered in the controller is invoked. Here, we will build the query
object needed for the server to process and call getResults
method in ResultsFactory
. The getResults
method returns a promise, which gets resolved when the response from the server is back. Assuming a success scenario, we will set $scope.results
to the search results from the server.
This modification to the $scope
object triggers an update on all instances of the results array. This, in turn, triggers the ng-repeat
directive on the HTML template, which parses the new results
array and generates the markup. And voila! The UI is updated with the search results.
Tip
Downloading the example code
You can download the example code files from your account at http://www.packtpub.com for all the Packt Publishing books you have purchased. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you. For this chapter, you can chat with the author and clear your queries at GitHub (https://github.com/learning-ionic/Chapter-1).
The preceding example shows how you can structure your code in an orderly fashion that can be maintainable and testable. Now, adding an extra image next to each search result is very easy, and any developer with basic knowledge of the Web can update the application.