Now, after developing the microservices, it would be interesting to see how the services offered by the Online Table Reservation System (OTRS) could be consumed by web or mobile applications. We will develop the web application (UI) using AngularJS/bootstrap to build the prototype of the web application. This sample application will display the data and flow of this sample project – a small utility project. This web application will also be a sample project and will run independently. Earlier, web applications were being developed in single web archives (files with .war
extensions) that contain both UI and server-side code. The reason for doing so was pretty simple as UI was also developed using Java with JSPs, servlets, JSF, and so on. Nowadays, UIs are being developed independently using JavaScript. Therefore, these UI apps also deploy as a single microservice. In this chapter, we'll explore how these independent UI applications are being developed. We will develop and implement the OTRS sample app without login and authorization flow. We'll deploy a very limited functionality implementation and cover the high level AngularJS concepts. For more information on AngularJS, you can refer to AngularJS by Example, Chandermani, Packt publishing.
In this chapter, we will cover the following topics:
Now since we are ready with our HTML5 web app setup, we can go through the basics of AngularJS. This will help us to understand the AngularJS code. This section depicts the high level of understanding that you can utilize to understand the sample app and explore further using AngularJS documentation or by referring to other Packt publications.
AngularJS is a client side JavaScript framework. It is flexible enough to be used as a MVC (Model View Controller) or MVVM (Model-View-ViewModel). It also provides built-in services like $http
or $log
using a dependency injection pattern.
MVC is well-known design pattern. Struts and Spring MVC are popular examples. Let's see how they fit in the JavaScript world:
MVVM is an architecture design pattern that specifically targets the UI development. MVVM is designed to make two-way data binding easier. Two-way data binding provides the synchronization between the Model and View. When the Model (data) changes, it reflects immediately on the View. Similarly, when the user changes the data on the View, it reflects on the Model.
A module is the first thing we define for any AngularJS application. A module is a container that contains the different parts of the app such as controllers, services, filters, and so on. An AngularJS app can be written in a single module or multiple modules. An AngularJS module can contain other modules also.
Many other JavaScript frameworks use the main
method for instantiating and wiring the different parts of the app. AngularJS does not have the main
method. It uses the module as an entry point due to following reasons:
Each AngularJS app needs to have a single module for bootstrapping the AngularJS app. Bootstrapping our app requires the following three parts:
app.js
) that contains the AngularJS module as shown:var otrsApp = AngularJS.module('otrsApp', [ ]) // [] contains the reference to other modules
index.html
file containing the reference to the JavaScript file with other AngularJS libraries:<script type="text/javascript" src="AngularJS/AngularJS.js"/> <script type="text/javascript" src="scripts/app.js"/></script>
Index.html
file that also contains an HTML element (typically <html>
) with the ng-app
(AngularJS directive) attribute having the value given in app.js
. AngularJS directives are prefixed with ng
(AngularJS): <html lang="en" ng-app="otrsApp" class="no-js">
.AngularJS.bootstrap(document.documentElement, ['otrsApp']);
.An AngularJS module has two important parts, config()
and run()
, apart from other components like controllers, services, filters, and so on.
config()
is used for registering and configuring the modules and it only entertains the providers and constants using $injector
. $injector
is an AngularJS service. We'll cover providers and $injector
in the next section. You cannot use instances here. It prevents the use of services before it is fully configured.run()
is used for executing the code after $injector
is created using the preceding config method. This only entertains the instances and constants. You cannot use providers here to avoid configuration at run time.Let's have a look at the following code:
.controller('otrsAppCtrl', function ($injector) { var log = $injector.get('$log');
$log
is an inbuilt AngularJS service that provides the logging API. Here, we are using another inbuilt service, $injector
, that allows us to use the $log
service. $injector
is an argument in the controller. AngularJS uses function definitions and regex to provide the $injector
service to a caller, also known as the controller. These are examples of how AngularJS effectively uses the dependency injection pattern.
AngularJS heavily uses the dependency injection pattern. AngularJS uses the injector service ($injector
) to instantiate and wire most of the objects we use in our AngularJS app. This injector creates two types of objects – services and specialized objects.
For simplification, you can say that we (developers) define services. On the contrary, specialized objects are AngularJS stuff like controllers, filters, directives, and so on.
AngularJS provides five recipe types that tell the injector how to create service objects – provider, value, factory, service, and constant.
As we have now some understanding of services, we can say that there are two common uses of services – organizing code and sharing code across apps. Services are singleton objects, which are lazily instantiated by the AngularJS service factory. By now, we have already seen a few of the in-built AngularJS services like $injector
, $log
, and so on. AngularJS services are prefixed with the $
symbol.
In AngularJS apps, two types of scopes are widely used: $rootScope
and $scope
:
$rootScope
is the top most object in the scope hierarchy and has the global scope associated with it. That means that any variable you attached to it will be available everywhere and therefore use of $rootScope
should be a carefully considered decision.$scope
as an argument in the callback function. It is used for binding data from the controller to the view. Its scope is limited to the use of the controller it is associated with.The controller is defined by the JavaScript constructor
function as having a $scope
as an argument. The controller's main purpose is to tie the data to the view. The controller function is also used for writing business logic – setting up the initial state of the $scope
object and adding the behavior to $scope
. The controller signature looks like the following:
RestModule.controller('RestaurantsCtrl', function ($scope, restaurantService) {
Here, the controller is a part of RestModule
. The name of the controller is RestaurantCtrl
. $scope
and restaurantService
are passed as arguments.
The purpose of filters is to format the value of a given expression. In the following code we have defined the datetime1
filter that takes date as an argument and changes the value in dd MMM yyyy HH:mm format like 04 Apr 2016 04:13 PM.
.filter('datetime1', function ($filter) { return function (argDateTime) { if (argDateTime) { return $filter('date')(new Date(argDateTime), 'dd MMM yyyy HH:mm a'); } return ""; }; });
As we have seen in the Modules section, AngularJS directives are HTML attributes with an ng
prefix. Some of the popular directives are:
ng-app
: This directive defines the AngularJS applicationng-model
: This directive binds the HTML form input to datang-bind
: This directive binds the data to the HTML viewng-submit
: This directive submits the HTML formng-repeat
: This directive iterates the collection<div ng-app=""> <p>Search: <input type="text" ng-model="searchValue"></p> <p ng-bind="searchedTerm"></p> </div>
In single page applications (SPAs), the page only loads once and the user navigates through different links without page refresh. It is all possible because of routing. Routing is a way to make SPA navigation feel like a normal site. Therefore, routing is very important for SPA.
The AngularUI team built UI-Router, an AngularJS routing framework. UI-Router is not a part of core AngularJS. UI-Router not only changes the route URL, but it also changes the state of the application when the user clicks on any link in the SPA. Because UI-Router can also make state changes, you can change the view of the page without changing the URL. This is possible because of the application state management by UI-Router.
If we consider the SPA as a state machine then the state is a current state of the application. We will use the attribute ui-sref
in a HTML link tag when we create the route link. The attribute href
in the link will be generated from this and point to certain states of the application which are created in app.js
.
We use the ui-view
attribute in the HTML div to use UI-Router: for example, <div ui-view></div>
.