Tuesday, March 27, 2012

Upgrading to angular 1.0.0 - compiler

I have been working on upgrading all of our client side libraries and such that were developed using angular (latest was 0.10.5) to the FCS release coming up (using the latest builds -1.0.0-rc3 as of this post).

There have been some massive changes since 0.10.5, so will be putting some of the updates here as reference.

One of the things that has changed is the initialization/bootstrapping of an angular app.

The majority of our angular based apps are loaded via xhr from OSGi bundles that are serving the content (statically via html streams) and being injected into existing UI framework.

Before this push, we were able to do something similar to:

$('#myContainer').load(url, function(responseText, textStatus, XMLHttpRequest) {
    ...
    angular.compile($('#myContainer'))().$apply();
    ...
});

This has changed now and can be accomplished a couple of ways.

A little background - to be explained in further as they are developed - is that the new upgrade introduces "modules" that are defined to encapsulate how an application should be bootstrapped, configured, and what services can be added.

So say if we have defined a module for the app called 'interfaceSettings':

var interfaceSettingsModule = angular.module('interfaceSettings' ['interfaceApp.services', 'interfaceApp.filters', 'interfaceApp.directives']);

(This is defining an angular module named 'interfaceSettings' that is also injecting the modules 'interfaceApp.services', 'interfaceApp.filters', interfaceApp.directives', which were defined previously).

So, for automatic bootstrapping, we can define our app directly in the element that is the root element of the app:

<div ng-app="interfaceSettings" id="ng-app" ng-controller="...">...</div>

The ng-app directive tells angular that this is the root of the application, and to use the module defined as 'interfaceSettings'.

You will also notice a repeated 'ng-app' call in the 'id' tag. This is to allow IE 7/8 to recognize this as well, since there are some issues with earlier releases not recognizing the app call (just dreaming of the day when don't have to do so much crap just because of IE shortcomings. They should have to do community service forever for releasing the normal junk they usually do. sigh....)

We can also still manually bootstrap it by taking the root element:

angular.bootstrap($('#interface_myContainer_container'),['interfaceSettings']);

Which will take the root element and compile it, using the module(s) indicated in the array.

This actually gives us some great flexibility in definitions, but will also allow us to just load in external apps and embed anywhere inside the existing framework.

To allow us to do this automatic bootstrapping though, we have to make sure to load in the angular lib inside the main framework. Before, the reference to the library was loaded with each loaded app.

A near future goal is to have the ability to define different elements of the web-based GUI based on OSGi bundles and angular as well, so this change to include the library by default is a good one anyway.