Tuesday, July 9, 2013

Dynamic Directives with Angular

Having recently embarked on a Single Page Application (SPA) for one of my clients, the technology landscape is pretty vast.  Without going into much detail, I settled on AngularJS as one of the many javascript libraries. Angular is pretty robust with a wealth of options required of spas.

[I looked at a few others, such as KnockoutJS and Durandal. While these are great JavaScript libraries, I found Angular provided most of the functionality I needed in a single JavaScript package.]

One angle of Angular is the concept of directives.  Directives, in a nut shell, are ways for the developer to build custom html tags, or add features to existing tags.  The purpose of this post is not to go into all of the details of directives, but to focus on one particular hurdle I recently had to overcome.

Problem: The information I need to display to the user must be in a variable format, based on an attribute of the object. Each view variation is presented by a related custom Angular directive. It can be challenging to dynamically assign the correct Template, or TemplateUrl from within the actual directive. I needed a way to select the correct directive for each row of data and render them all on the screen at the same time.

First, I’ll start with the data.  In this example, I have an array of five objects.  The only notable thing is the driverType.  There are three different types, which will determine the Angular Directive I wish to present to the user.  The types are driverOne, driverTwo, and driverThree.  Nothing special.

 function fetchDriverData() {
        return [
            { id: '001', name: 'Sample Data1',  driverType: 'driverOne' },
            { id: '002', name: 'Sample Data2',  driverType: 'driverTwo' },
            { id: '003', name: 'Sample Data3',  driverType: 'driverThree' },
            { id: '004', name: 'Sample Data4',  driverType: 'driverOne' },
            { id: '005', name: 'Sample Data5',  driverType: 'driverTwo' }

The array of objects is available to my HTML by way of an Angular $scope.  It is injected into my view’s controller and can be accessed from any number of ngViews for my SPA.  If you are not familiar with ngView, there are a number of good resources on the web.  Views are a pillar of SPAs, so it is best that you become familiar with them.

The magic for dynamic directives comes into play with three angular directives,
The first thing I want to do is iterate over my driver collection.  I’ll use a simple repeater:
<div ng-repeat ="driver in drivers">

Within my repeater, I’ll use the ngSwitch to selectively make use of the three different custom Directives.  The switch will be on each driver from the driver repeater.
<div ng-switch="driver.driverType">
(Remember: drivers is the collection and driver represents a single item within the collection)

Now all I need to do is identify each condition, or driverType.
< div ng-repeat ="driver in drivers">
< div ng-switch ="driver.driverType">
< div ng-switch-when ="driverOne">< div class ="driver-directive-one" driver ="driver"></ div ></ div >
< div ng-switch-when ="driverTwo">< div class ="driver-directive-two" driver ="driver"></ div > </ div >
< div ng-switch-when="driverThree">< div class ="driver-directive-three" driver ="driver"></ div ></ div >
< /div >
< /div >
The highlighted div tag represents one of my custom directives, driverDirectiveTwo

Creating custom directives is a fantastic way to help provide a separation of concerns within your web based application and to provide the potential for reusability. Directives are also a great way to provide a means for testing your code, which is always a good idea. I hope this post was helpful and sparked options for the dynamic, data-driven, aspects for your own Single Page Application.