AngularJS

Every once in a while, you are introduced to a new technology that improves your day to day life as a Web developer so much, you can't stop talking about it. For me these moments are few and far between. Discovering and learning to work with Ruby and Rails was one of the bigger ones in the last few years.

More recently I have been introduced to AngularJS. A web framework that turns your HTML in an expression power house.

A short introduction

Directives for HTML as a DSL

AngularJS comes with a great basic framework that allows you extend your HTML with powerful constructs expressed through markup. These constructs allow you to semantically enrich your HTML to express it is something, or should do a particular thing, without polluting it with unnecessary visual clutter.

What's a Domain Specific Language (DSL)?

Domain specific languages are all around you. It's simply a way to express what you want to express without being bogged down by (all of the) idiosyncracies inherent to the platform you're working on.

A great example of a DSL we're all familiar with is HTML. This markup language was created to satisfy the needs of authors of academic articles in exchanging scientific articles through the Internet. To this end, a language was created that allows you to markup your text with certain simple commands. These markup elements are part of a DSL that allow you to complete that specific task with great ease. All these elements bundled together are called HTML. The web exploded in popularity, not only in academic circles, but also amongst normal consumers. Slowly but surely, HTML was being used for things it wasn't meant for.

Now, after many years of abuse of a perfectly good standard, Angular has come along and says "Stop the abuse of existing elements, instead, add to your HTML by extending its DSL". To allow this, the developers created something called directives.

What are directives?

So, we now know that to extend HTML's markup functionality we can use Angular's directives. These directives are basically encapsulated Javascript scopes that allow you to describe:

  • how the directive should be used
  • the services it requires
  • the information it requires to function
  • what the HTML that will replace the directive would look like; and finally
  • how to respond to events that have been fired from within the directive's HTML.

There are a number of ways you can incorporate a directive in HTML, let's say we are creating one called poll. Then these are the ways it could be called:

  • as an element: <poll></poll>, this method is the clearest but doesn't work well with all browsers (read: internet explorer also spoiled this goodie for us)
  • as an attribute: <div poll></div>
  • as a CSS style: <div style="poll: value"></div>

So, based on what the directive does, you can integrate it into different places of the markup.

Advantages

There are quite a few advantages to using directives:. It allows you to shift your thinking from, "how does my problem space map onto HTML" to "How can I extend HTML to be a good home for my problem space". This paradigm shift is essential to anyone that wants to really deal with the problem instead of limitations of the underlying framework. Not only does it free up the developer's mind, but I'm quite sure HTML itself is quite happy to be extended insteafd of being abused left and right.

If you intend to you use Angular in more than one of your web applications directives are a great way to make things more reusable. Angular supports a module concept that allows you to put directives (and all kinds of other constructs such as services and factories) into a different namespace. By simply creating a bundle of these components and including them in any of your applications, you have a surefire way to reusing your code, thereby extending the likelyhood that you will have to write something from scratch.

The Angular community is quite vibrant, but most of all knowledgeable. As someone that only recently started creating Angular applications, I found that there is a great deal of quality help to be found online in forums but also in the online documentation which is quite great.

Architectural separation

One of the beautiful things Angular allows you to do is create a clear and definite separation between client-side code and server-side code. The extensive possibiities and easy of use offered by the powerful markup extensions reduce the necessity for your frontend code to be generated server-side to virtually zero.

The practical implication of this, is that the server turns into a data provider. This means that the server no longer is responsible for rendering the correct pieces of HTML depending on the state of the model. This means that the server only has to deal with getting the right information at the right URIs, and dealing with mutations and potential errors in these mutations in an elegant manner.

So, what does it take to adopt this reasonably new development paradigm? Where do we put the bridge between the new and the old? Of course, there are no silver bullet answers to these questions. The one thing they have in common is the following. There has to be only one entry point through which the initial HTML for the application is loaded.

For example, in a Rails application, you would only need one controller, with one action, that displays the initial template with the instructions to load angular, and where to load the first view. This doesn't mean that it is not possible to use angular hodge podge in existing Web applications, but when you're doing greenfield development, there's hardly anything else you'd need.

A cool side-effect of the fact that all the view building and handling is performed client-side, is that it is now possible to create small application bundles. These application bundles would contain:

  • HTML (annoted with angularjs)
  • Javascript implementations of the behaviors
  • Assets, such as images and CSS

If setup properly, it will be possible to include a single line of script code on site A that loads and uses resources from site B without any server-side modifications. Imagine the possibilities this brings with regards to little portlets, rich advertisement experiences etc. Integrating your code into someone else's site has never been easier.

Talking directives

If, like me, you've discovered that directives are the way everthing should have been working like since day one, you might have started to use them here and there in your code. Now, there are certain situations in which it becomes necessary for your directives to share information, or signal certain method calls. This is where it can become quite tricky. Of course, Angular has a number of ways to deal with this, but picking the right one might be quite the chore.

These are the methods I've uncovered that work quite well without resorting to keeping track of stuff in some global variable somewhere:

  • shared data; useful when there's only data to be shared
  • event broadcasting; if you're a big fan of jQuery's bind/trigger strategy, you'll love this one
  • one way signal; where a directive gets to signal another directive, but not the other way around
  • passing an interface; useful in a situation where there is a parent object that knows of the existance of two or more child directives. One could simply pass around an object with an interface implementation.
  • signal handlers; inspired by passing around the interface, but feels more angularesque, as it passes around methods on the scope, callable from the directive /with/ parameters.

Shared data only

Imagine a scenario where there is a controller, that in its view has two directives. These directives need to share information, e.g. a search result list wants to share the selected result with a result view component.

Using the '=' type of scope attribute in the directive's declaration, one can make a pathway between information in the controller and a directive. So, to make the shared data work, you define a variable in the controllers scope, initialize etc., then when calling the directive, fill the attribute that has the '=' assigned to it with a reference to that variable.

 

									yourModule.directive("myDirective", function() {
									 return {
									     restrict : 'E',
									     scope : {
									         model : '='
									     },
									     link : function(scope, element, attrs) {
									         // put your template right
									     }
									 };
									});
									

When one of the directives changes the content or reference of the controller's variable, all the other directives that also have this variable in their scope, will be notified of the changes, and update their views accordingly.

Broadcast

The second approach I'd like to highlight has to do with subscriptions to events on an event bus.

Like jQuery's bind/trigger mechanism, Angular contains a construct that allows you to subscribe to events, and fire events. A downside of this approach is that it isn't quite possible to pass information from one side to the other. The last approach this article mentions is a solution to that.

To be honest, I'm not a great big fan of these kinds of systems because they might seem alluring at first, but once you really start to use them in quite a few places, maintaining the overview of which component listens to what, and which elements are called when upon what event is just a nightmare straight from the fiery pits of hell.

Since I'm not a big fan of this approach, I will not entertain you with an example ;-)

Passing an interface

Another possibility to be able to communicate between a child directive and a parent controller is passing a variable to the directive that gets bound on the scope. This approach is very similar to the first approach, however, the contents of this variable is quite different.

Instead of having a synchronized model which only contains model information, of course, it's also possible to pass a complete object to the directive. Because of the nature of javascripts lexical scoping, you will be able to set information in the controller while calling from the directive's scope.

 

									$scope.behaviorImpl = {
									 method : function() {
									     console.log("Can access scope from here");
									     console.log($scope);
									 }
									};
									
									yourModule.directive("myDirective", function() {
									 return {
									     restrict : 'E',
									     scope : {
									         behaviorInterface : '='
									     },
									
									     link : function(scope, element, attrs) {
									         scope.behaviorInterface.method("you can even pass stuff");
									     }
									 };
									});
									

While this is a perfectly legitmate approach to passing around methods it somehow feels less angularesque than some of the other approaches detailed here.

One-way signal

In a situation where there's a controller that needs to be signalled that a certain event has happened (without actually providing any additional information related to that event), one could consider using this approach.

A nice example of a situation in which this could be useful is a multi-page form that has a "Cancel" button. Each step in the multi-page form has its own directive. Every page has a next and cancel button at the bottom of the page. The process that gtuides the multi-page form needs to know when the information in that form has been completed, or when the user decided to cancel the entire form submission.

Typically a situation where the directive does not need to pass any additional information, and simply needs to signal what happened.

As with the first approach, there is a neat scope trick you can do when defining your directives. When defining how to bind attributes in the invokation to the scope, it's possible to state that a certain attribute actually is an executable code-block. To do this, use "&".

									yourModule.directive("signalDirective", function() { return { restrict : 'E', scope : { mySignal : "&" },
									     controller : function($scope) {
									         angular.extend(scope, {
									             somethingWasClicked : function() {
									                 $scope.mySignal();
									             }
									         });
									
									     }
									
									 };
									
									});
									

 

Inside the directive, the scope will now have an additional attribute that is actually a callable function. When called inside the directive, it executes in the scope of the view that instantiated the directive. So! This means that we can have the following work:

Pretty neat huh? Of course you can also pass variables that are on the controller's scope to the controller function. The only limitation is that there is no way for the directive to pass anything of importance to that particular function.

Signal handlers

So, for our final approach we're going to take the previous approach up one level. Literally. Of course the previous method is quite nice, because it allows you to execute certain methods from a different scope than the current scope. Unfortunately, as I mentioned, it has the downside of not being able to pass information from the directive to the other scope. Wouldn't it just be great if we could execute a method in a different scope (doesn't really matter what scope) and pass some relevant information to it at the same time. This would greatly increase the usefulness of a directive as a full-fledged self-contained data-driven entity.

To do this, we make a small adjustment to the code from our previous example. Instead of executing a function in our '&' bound scope function we make Angular return a reference to our function. Since we now have a reference to the function, we can actually call the function with our own parameters, effectively enabling us to pass information between controller and directive.

									yourModule.directive("signalDirective", function() {
									 return {
									     restrict : 'E',
									     scope : {
									         myFunctionPtr : "&"
									     },
									
									     controller : function($scope) {
									         angular.extend(scope, {
									             somethingWasClicked : function() {
									                 $scope.myFunctionPtr()("right from the directive");
									             }
									         });
									     }
									 };
									})
									

This, combined with the data-sharing approach look very Angularesque, and is basically everything you're ever going to need. In fact, think twice before you use this approach, maybe the information you want to pass back to the controller could have easily been provided for with a shared variable. Remember, it is possible to put a watch on a model variable.

So, there you go, this should help your communication skills. If you have any questions don't hesitate to contact me.

Also Read

SCAR: a Java scaffolding solution

By The Digital Team on 26 September 2021

Websocket Handshake

By The Digital Team on 26 September 2021

A centralized interface specification

By The Digital Team on 26 September 2021