Laying a foundation of AngularJS project

I recently worked on my first AngularJS project. It was a bit of surprise to find out how much work you need to put into building a set of generic components for your project.

AngularJS claims to be a toolset for building frameworks rather than a framework on its own. Even though it provides plenty of core functionality out of the box (e.g. routing, data-binding, etc.), you will still need to build many components for common tasks such as loading panes, notifications, etc.

The project that I worked on was an intranet type application, used mainly to view and edit various types of data. As such, most of the components that I describe below deal with improvements to form usability.

To give you an idea which features are not in AngularJS, I describe some of the custom components that we built for the project. For some of the components, I provide implementation ideas while for others I only provide design ideas but both should help you get started on your first CRUD AngularJS application.

Loading Pane

HTTP API is an essential part of single page applications. It is a good practice to inform users when the application is loading data from the server to correctly display the user interface. In such cases, the loading pane directive comes in handy as it conditionally displays a loading indicator on a semi-transparent pane covering the element.

See the Pen Chagc by Alexander Puchkov (@apuchkov) on CodePen.

Input Throbber Directive

It is always a good idea to indicate, with a spinning icon, that something is happening behind the scenes in relation to input.

This Input Throbber directive configures input elements to display a spinner. Other directives, such as async validators, can then use it when needed.

See the Pen lwkdq by Alexander Puchkov (@apuchkov) on CodePen.

Dirty Form Notifier

This custom directive monitors if the user wants to leave a page ($locationChangeStart event) or wants to close a browser window ($window.onbeforeunload event). In these cases, it checks if any form data was changed and if so, displays a confirmation message. It is a good idea to make such a directive rely on the “form” directive so that it can access the form’s $dirty flag as shown in the demo below.

See the Pen pLDGe by Alexander Puchkov (@apuchkov) on CodePen.

HTTP Interceptors

We created custom HTTP Interceptors to transform Http requests or responses in some way.

JSON Date Interceptor

Single page applications get data in JSON format from API endpoints. JSON itself doesn’t specify how dates should be represented. By default, dates returned by the server become a string on Angular’s scope. It is much more flexible to use a date in the form of a date type as it can be compared, adjusted, and serialized more conveniently. This date interceptor checks every property of response returned from the server. If a property looks like a date, then it will be converted to a date type.

See the Pen JqCtL by Alexander Puchkov (@apuchkov) on CodePen.

Http Error Interceptor

We wanted to notify a user if the app cannot communicate with the server when getting or saving data. This interceptor checks if the response from an Ajax call has an error status code.

See the Pen tBDcG by Alexander Puchkov (@apuchkov) on CodePen.

Exceptions Logger

Historically, server errors were logged but JavaScript errors were left without much attention. As single page applications become more and more common, application logic remains on the client-side and so we should pay serious attention to JavaScript errors.

There are a few web services available to log JavaScript errors but we decided to store these on the server side.

To implement custom exception handling functionality, you will need to override Angular’s $exceptionHandler factory.

Field Directive

As I indicated earlier, the main focus of our application is data entry. Because the application contains many fields, we wanted to make it very easy to add fields or to change the functionality across the application.

With these goals in mind, we created a custom Field directive. This Field directive

  • makes HTML declarations more expressive by removing the HTML clutter of redundant “name” and “id” attributes as well as “for” attribute on label tags.
  • keeps HTML templates in one location allowing for easier refactoring in the future.
  • improves validation behavior by:
    • displaying errors in tooltips rather than inline thereby pushing all the elements down.
    • displaying a message only after the user completes their input (by default, Angular would show an error as soon as the user begins to type an email address).
    • displaying a summary of all validation errors in notification.

The following example shows to use this directive:

Compare the above example to the Angular default way:

Needless to say, it was the trickiest directive to implement. We used examples and ideas from the excellent book, Mastering Web Application Development with AngularJS. If you are planning to implement something similar, you should get a copy of this book.

Focus Me Directive

It is a good practice to set focus on the first input of a modal window and the Focus Me directive does precisely that.

Also refer to the implementation on Stack Overflow found at http://stackoverflow.com/a/14837021/1689049

Lazy Include

Currently, AngularJS 1.2 cannot load a controller or a template on the fly once the application is loaded. Such a feature was needed in our application to change the functionality and the look of one page by dropping in a new controller and template files after the application was deployed.

Multiple implementations of this feature can be found; almost all of those implementations rely on internal Angular variables which, in a perfect world, should not be accessed from the application.

Our implementation is based on the one found at http://stackoverflow.com/a/15292441/1689049. This implementation is working well and seems very stable.

Multiple languages support

Choosing the right approach to support content in multiple languages caused a much debate and brainstorming sessions. Content has to be translated in both controller / services strings and in templates. While JS strings translation is more straight-forward, templates can have translatable content inside of a HTML tags or as a HTML attribute (e.g. <input placeholder=”First Name” /> ).

Out-of-the-box AngularJS only helps with localization of date, numbers, and currency. It is left up to the developer how to implement multiple languages.

When deciding on the best approach, we evaluated a few options:

1.   Using a custom filter

The main problem with this approach was the performance as such a filter would add a new watch expression that is evaluated on every digest cycle.

2.   Preprocessing templates

This would allow us to create our own syntax for translatable strings in templates and preprocess them with the build system. An example of a template follows:

This would also solve a problem with translatable attributes:

The second approach seemed to be the best option but it required the build system to run all the time during the development of the application. Before you could see a change in the browser, the build system would need to process all the templates. We felt that this would slow down and complicate the development process.

Custom directive

The approach that we ended up with is a custom directive which we called res (from resource). The following are a few examples:

Our res directive has the following advantages:

  • String replace happens only once during the compile phase so there is minimal impact to the performance.
  • The syntax is relatively short.

But it has the following disadvantages:

  • It can’t use be used in attributes such as “placeholder” or “title”. This is definitely a limitation but we have yet to experience any major problems because of it.
  • Custom directives, such as “action” in the above example, need to be updated to take the resource key and get content internally.

Modal Windows

Angular UI Bootsrap Modal provides great functionality. We created a custom service on top of it to add a few features as follows:

  • Declare all modals (with their controllers, templates, and settings) in a single place similar to how routes are defined.
  • Render modal contents inside a template with a common header and footer. This removed repetitive markup from modal views making them more look like views for regular pages.
  • Define and pass parameters to modal. We defined some common parameters for modals in their declaration and then extended modal parameters when invoking it.

Notifications

Interactive web applications should inform users when operations succeed or fail. We created a custom service to render notifications on screen. It works similar to Toaster but has a custom template and extra functionality.

One of the extra features is a special type of notification called progress which informs the user that an operation is in progress and then displays as a success or as an error. This is when single page applications allow for a better user experience. Users can begin an operation in the background, navigate around pages, and then be notified when it finishes.

Another feature is when the same notification fired multiple times we increase a counter in already displayed notification, instead of displaying multiple identical notifications.

Numbers Only Directive

Because certain inputs should accept only numbers, we created a custom directive which filters out any non-numeric input. This directive adds a custom function to ngModelCtrl.$parsers pipeline that intercepts the input and strips out non-numeric characters.

See the Pen ILjFr by Alexander Puchkov (@apuchkov) on CodePen.

Date Picker

We used Kendo UI widgets that include bindings for AngularJS. We used this without any modifications.

Title Service

Each page should have a different browser title to provide better user experience. It is easy to create a custom service to set a browser title.

Summary

I hope that after reading this article you have a better understanding of the components you need, other than AngularJS itself, to lay a good foundation for your application.

Before building my first angular application, I didn’t realize how many basic features of an admin type application are missing in Angular and therefore had to be created. None of these features are absolutely necessary but without them, the application would not be as user friendly.

The great thing about AngularJS is that it provides a great framework. By extracting these features to directives and services, your page controllers and templates will be more expressive and focused on business logic rather than plumbing.

Such components can be easily migrated from one project to another.

  • Alexis Toby

    Hi,
    In numbersOnly directive you use “numbersOnly” as function name and in HTML tag its is like numbers-only. How it is get linked.
    Thank you.

  • http://www.apuchkov.com Alexander Puchkov

    Angular normalizes an attribute name to determine which elements match which directives. Read more here: https://docs.angularjs.org/guide/directive#normalization