ERNI Technology Post No. 54: AngularJS: A complete client-side solution for ERNI Info App

What is ERNI Info App?

The Info App is a web application optimised for mobile devices that provides employees with access to information about their company and their work environment while on the move. This information is typical of what would be represented on a company intranet.

The Info App serves as a central hub, directing employees to use internal applications, media or portals (regarding company news, events, vacation requests and other valuable links).

Figure 1 - ERNI Info App: Home Screen

The user interface of the Info App has been developed with AngularJS. This article explains how we used the power of the AngularJS framework to develop the application.

AngularJS

AngularJS is an open source web application framework wrapped around native HTML/JS/CSS technologies. It augments the web development techniques with patterns and practices that help web application development become more mature and able to handle more and more responsibility that can be shifted from the back end to the front end. Its goal is to augment browser-based applications with model-view-controller (MVC) or model-view-view-model (MVVM) capability. It helps us to make both development and testing easier.

Benefits of using AngularJS

  • AngularJS lets you extend HTML vocabulary for your application
  • With AngularJS, you have to write less code
  • Using AngularJS frees you from low-level DOM manipulation and instead you can declare how the UI should change as your application state changes

Front-End Structure

We followed the best practices recommended by the Angular team in the syntax, conventions and structuring of the files. To give you an example, here is what the directory structure looks like:

The key is to create one folder per feature, for instance, the company events page. Then inside the folder, we have everything that relates to the event. Previously, all the JavaScript codes were found in a single file named “app.js”. But this is not ideal, because it is harder to read and maintain, so we separated them per file.

event.module.js: angular module (specify module and its dependencies)
event.controller.js: angular controller
event.service.js: angular client service
event.tpl.html: html template that relates to the controller

Templates

In AngularJS, templates are written with HTML that contains Angular-specific elements and attributes. The HTML vocabulary is extended to contain instructions on how the model should be projected into the view. In the company events page, we used the event.tpl.html to render the view.

<div class="event-list">

     <ul>

          <li ng-repeat="eventItem in event.eventList">

               <a ng-href="#eventdetail/{{eventItem.Id}}/event">

                    <div class="event-item-container">

                         ...

                    </div>

               </a>

          </li>

     </ul>

</div>

Directives

A directive in AngularJS is a meaningful name that adds additional behaviour to a DOM Element. It is used to extend HTML elements, attributes, comments or classes. AngularJS has a large set of built-in directives and you can also create custom directives. Here are some built-in directives we used in the application:

  • ng-bind-html – Used to bind inner HTML property of an HTML element. In the How to Survive In page, the content has HTML tags, so we used the ng-bind-html directive to evaluate the expression.

<span ng-bind-html="miniatureItem.Content"></span>

  • ng-class – Allows you to dynamically set CSS classes on an HTML element by databinding an expression that represents all classes to be added. In the Company News page, we have a CSS class to show the Categories list:

<nav class="navdrawer-container" ng-class="{'open': today.openSidebar}">

  • ng-show – It works based on expression: if true, then the element is shown. In the Company News page, we used this directive to determine whether to show the latest top news or not. It should only happen when all articles are shown or when the top news page is open.

<div id="topnewspage" ng-show="today.showAll || today.showTopNewsOnly">

  • ng-href -It is used to dynamically bind AngularJS variables to the href attribute. In the Vacation Overview page, we put in an anchor tag to redirect to the vacation detail page. We used the ng-href directive to handle the vacation item ID parameter.

<a ng-href="#vacationdetail/{{vacationItem.Id}}">

  • ng-model – It is used to bind an input, select, textarea or custom form control elements with model property. In the Phonebook page, we used ng-model to bind the keyword property.

<input type="text" name="keyword" ng-model="phonebook.keyword" placeholder="Enter keyword" required />

  • ng-submit - It is used to bind angular expressions to onsubmit events. Since the Phonebook page has the binding of the keyword property, we used that model in the ng-submit.

<form name="phonebookForm" ng-submit="phonebookForm.$valid && phonebook.searchPhonebook(phonebook.keyword)" novalidate>

  • ng-repeat – It is used to loop through each item in a collection to create a new template. We applied ng-repeat in almost all the collections in the app. The Phonebook results page is one example:

<ul>

     <li ng-repeat="resultItem in phonebookresults.resultsList">

          <div>

               <div>

                    {{resultItem.Name}}

               </div>

               <div>

                    Shortname: {{resultItem.ShortName}}

               </div>

               <div>

                    Work phone: <a ng-href="tel:{{resultItem.WorkPhone}}">{{resultItem.WorkPhone}}</a>

               </div>

               <div>

                    Mobile phone: <a ng-href="tel:{{resultItem.MobilePhone}}">{{resultItem.MobilePhone}}</a>

               </div>

               <div>

                    Email: <a ng-href="mailto:{{resultItem.Email}}">{{resultItem.Email}}</a>

               </div>

          </div>

          <div class="nav-gray-line"></div>

     </li>

</ul>

  • ng-src – It is used to dynamically bind AngularJS variables to the src attribute. In the Company News page, we used the ng-src directive in the img tag to handle the first image of the article.

<img ng-src="/api/TodayArticle/image/img?path={{today.topOneArticle.FirstImage}}" alt="thumbnail" />

  • ng-if – It is used to remove the element from the DOM when the condition is false and adds the element back once the condition becomes true. In Company News article page, the indicator that the article is loading has ng-if directive.

<div id="loaderAnimation" ng-if="article.loading">

  • ng-click – Allows you to specify custom behaviour when an element is clicked. In the Company News page, we have an icon that shows the Categories list when you click it.

<div ng-click="today.switchSidebar()">

     <img src="images/big-icons/section-menu.png" alt="Section Menu"/>

</div>

Filters

A filter formats the value of an expression for display to the user. They can be used in view templates, controllers or services and it is easy to define your own filter. Here are some filters we used in the application:

  • date – Format a date to a specified format. In the Company Events page, the date is formatted to show the month in MMM format.

<span class="event-item-date-month">

     {{eventItem.DisplayStartTime | date:'MMM' }}

</span>

  • filter – Select a subset of items from an array. In the Company News page, the articles are filtered into different categories.

  • limitTo – Limit an array into a specified number of elements. Now, the default count of the number of articles per category is 5 and then when the user selects the category page, it will show 10 articles.

<div class="container-categorylist">

     <ul class="global-li-none">

          <li ng-repeat="entry in today.entries | filter:{Category:categoryName} | limitTo:today.subsiteCount">

               <a ng-href="#article/{{entry.Category}}/{{entry.Id}}/today">

                    ...

               </a>

          </li>

     </ul>

</div>

Module

The module is the place where the dependencies for the app are defined. In order to securely evaluate the HTML elements for the ng-bind-html in the How to Survive In page, we included the ngSanitize in our module’s dependencies:

angular

     .module('infoApp.howtosurvivein', ['ngSanitize']);

Data Binding

Data-binding in AngularJS apps is the automatic synchronization of data between the model and view components. When the model changes, the view reflects the change, and vice versa. In the Vacation Request overview page, the status title changes whenever the user chooses a status.

<span>{{vacationrequest.selectedStatus}}</span>

Controller

In AngularJS, the controllers represent the business logic behind views. In the Phonebook page, the searchPhonebook function is called whenever the user clicks the Search button.

(function () {

    'use strict';

    angular

        .module('infoApp.phonebook')

        .controller('PhonebookController', PhonebookController);

 

    PhonebookController.$inject = ['$location'];

 

    function PhonebookController($location) {

        var vm = this;

 

        vm.searchPhonebook = SearchPhonebook;

 

        function SearchPhonebook(keyword) {

            $location.path("/phonebookresults/" + encodeURI(keyword) + "/phonebook/0");

        }

    }

})();

Dependency Injection

The Angular injector subsystem is in charge of creating components, resolving their dependencies and providing them to other components as requested. In the company event detail page, we used the $routeParams service and injected it into the controller:

(function () {

    'use strict';

    angular

        .module('infoApp.eventdetail')

        .controller('EventDetailController', EventDetailController);

 

    EventDetailController.$inject = ['EventDetailService', '$routeParams'];

 

    function EventDetailController(EventDetailService, $routeParams) {

        var vm = this;

       

        EventDetailService.getEventItem($routeParams.id).then(function (data) {          

            vm.eventItem = data;           

            return vm.eventItem;

        });      

    }

})();

Routing

Application routes in Angular are declared via the $routeProvider, which is the provider of the $route service. To access the media page, the user clicks on the Media icon, and then the #/media route expression is issued to the routeProvider, which then does the corresponding routing.

(function () {

     'use strict';

 

     angular

          .module('infoApp')

          .config(config);

 

     config.$inject = ['$routeProvider'];

 

     function config($routeProvider) {

          $routeProvider.when('/', {

               templateUrl: 'app/home/home.tpl.html',

               controller: 'HomeController as home'

          })

          .when('/media', {

               templateUrl: 'app/media/media.tpl.html',

               controller: 'MediaController as media'

          })           

          .otherwise({

               redirectTo: '/'

          });

     }

})();

Service

AngularJS services are substitutable objects that are wired together using dependency injection. The $http service is a core AngularJS service that facilitates communication with the remote HTTP servers. In the Company Events page, we retrieved all the company events using the $http service.

event.controller.js

EventService.getEventList().then(function (data) {

     vm.eventList = data;

     return vm.eventList;

});

event.service.js

function EventService($q, $http, $location) {

     return {

          getEventList: getEventList

     };

 

     function getEventList() {

          var url = '/api/event/getAll';

           

          return $http.get(url, { cache: true })

               .then(getEventListComplete)

               .catch(getEventListFailed);

 

          function getEventListComplete(response) {

               var eventList = response.data;

               return eventList;

          }

 

          function getEventListFailed(error) {

               $location.path('/error');

          }          

     }

}

Conclusion

At the start of development of the Info App, I was just an AngularJS beginner. With the help of colleagues and other resources, I was able to structure the files better and the codes became easier to read and maintain. I also utilized the capabilities of AngularJS. The front end can already handle some of the server-side codes. This is indeed a complete client-side solution for the project.

I learned a lot from this experience, and with this article, I would like to share this knowledge with everyone.

References

[1] https://angularjs.org/

[2] https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md

posted on 16.03.2016
Categories: 
by: Princess Diana Ongchangco