AngularJS And Something For The Designers In My Life

This post is for all the designers in my life. I love AngularJS because as a developer it just makes sense but I am certain it is an entirely confusing and brave new world for some people.

The Backstory

This post was inspired by a series of conversations that I have had with one of my best buds, Shane Mielke, over a project that I am helping him out on. So before we go any further, I encourage you to check out his protfolio at http://www.shanemielke.com/work.php and you will see that he has some serious chops. He is rock solid when it comes to jQuery but it gets totally fuzzy when it comes to writing that same code in AngularJS.

I have a TON of friends who fall into this category. Awesome designer? Check! jQuery skills? Check! AngularJS? Uhhhhhh…. what?

So! I am going to show you a very gentle way to take something you would write in jQuery and convert it into something that doesn’t explode the AngularJS universe.

jQuery Events

For starters, it is important to mention the relationship that AngularJS has with jQuery. AngularJS comes with a subset of jQuery right out of the box. If you have included jQuery in your document then AngularJS will defer to that version of jQuery. This kind of cooperation right out of the gates is really handy.

I am going to give you the condensed version immediately so that if the light goes on and you cannot wait to go write code, you are not obligated to finish. I love designers as much as AngularJS does. Believe dat!

The simplest way to convert jQuery code into AngularJS is to create a directive and put that code in the link function of that directive.

This does not solve any architecture problems per se and there are some ways to optimize your directives but! this is going to get you started and the side effect is that you will have portable code. Watch this magic trick!

Let us take the click example from the jQuery docs via http://api.jquery.com/click/ and convert it into AngularJS.

First Paragraph Second Paragraph Yet one more Paragraph <script> $("p").click(function () { $(this).slideUp(); }); </script>

So we have all seen some variation of this theme a gazillion times. Target some HTML element and add an event handler to it that does something. The stage has been set.

So first things first, we bootstrap the AngularJS application with ng-app and the module name we want to load.

<html ng-app="myModule">

And then we hint at something amazing.

var myModule = angular.module('myModule', []); myModule.directive('slideUp', function () { var linker = function (scope, element, attrs) { // WAIT FOR IT! }; <pre><code>return { restrict:'A', link:linker } </code></pre> })

So I have created a directive called slideUp and we are going to put some DOM manipulation code in place to fulfill its destiny. You may want to sit down for this.

myModule.directive('slideUp', function () { var linker = function (scope, element, attrs) { element.on('click', function () { $(this).slideUp(); }); }; <pre><code>return { restrict:'A', link:linker } </code></pre> })

What the!? That looks almost like the jQuery code. True story bro! The difference is that the parameter element is already a jQuery object so we don’t have to query it via $( ).

That is all nice and wonderful but how do we use it?

<p slide-up>Second Paragraph <p slide-up>Yet one more Paragraph

Special Note: AngularJS converts camel case directive names into snake case and so slideUp becomes slide-up.

So that was easy! But here is the really cool part. You can now use that directive to ‘decorate’ other elements.

<p slide-up>Second Paragraph <p slide-up>Yet one more Paragraph <div class="box" slide-up></div>

With no modification, I simply added slide-up to my div tag and it worked exactly the same. This is what I mean by ‘portable’.

A Few Variations

I am going to show you a few quick variations to get the wheels turning. I am only going to explain the interesting parts of each example and not belabor the redundant bits.

The next series of examples are going to be built around jQuery click event and the animate function. The premise is fairly simple. I want to animate an element in some direction when I click it.

For reference purposes you can see the full code here:

https://github.com/simpulton/angular-designers

Let us create a directive called animateRight.

myModule.directive('animateRight', function () { var linker = function (scope, element, attrs) { // So far so good. }; <pre><code>return { restrict:'A', link:linker } </code></pre> })

Lets add in the click handler.

myModule.directive('animateRight', function () { var linker = function (scope, element, attrs) { var right = function() { // Well THAT was easy } <pre><code> element.on('click', right); }; ... </code></pre> })

And the animate part.

myModule.directive('animateRight', function () { var linker = function (scope, element, attrs) { var right = function() { // We move it right by increasing the distance on the left - go figure $(this).animate({ left: '+=150' }) } <pre><code> element.on('click', right); }; ... </code></pre> })

And this is how we decorate the DOM.

<div animate-right class="box"></div>

And for fun let us create a variation that moves the element down.

myModule.directive('animateDown', function () { var linker = function (scope, element, attrs) { var down = function() { $(this).animate({ top: '+=150' }) } <pre><code> element.on('click', down); }; ... </code></pre> })

So you may have noticed this bit of code that says restrict:’A’ and wondered what in the world that is for. That essentially tells the directive that it can only be used as an attribute. You can also use E for element and C for class.

And since I brought it up, let me show you how a class directive works.

myModule.directive('animateRightClass', function(){ ... <pre><code>return { restrict:'C', link: linker } </code></pre> })

Change A to C and give it a new name for fun and drop it in your HTML. Bam!

<div class="box animate-right-class"></div>

And one more example for the road! You may have noticed the scope and attrs function being passed in to the link function. Do they actually do something? Well yes they do! Let us create a directive of the more dynamic variety.

<div animate="right" class="box"></div> <div animate="down" class="box"></div>

We are now passing in the direction that we want the element to animate.

Let us create the animate directive.

myModule.directive('animate', function(){ var linker = function(scope,element,attrs) { // BY NOW THIS HAS GOT TO BE BOOOOOORING! }; <pre><code>return { restrict:'A', link: linker } </code></pre> })

Scope is the current scope of the directive and attrs is an array of all the attributes on the element the directive lives on. So in the example above the way to get the value of what direction you want the directive to animate you simply refer to it as attrs[‘animate’].

We are also going to create some functions on scope that we can dynamically reference in the event handler.

myModule.directive('animate', function(){ var linker = function(scope,element,attrs) { scope.up = function() { // You know what to do here } <pre><code> scope.down = function() { // You know what to do here } scope.left = function() { // You know what to do here } scope.right = function() { // You know what to do here } var direction = attrs['animate']; element.on('click', scope[direction]); }; ... </code></pre> })

My favorite part of all this is that we are playing to JavaScript’s strength and doing some dynamic function referencing which is really cool!

Conclusion

I have walked you through a series of examples that shows how easy it is to pull your jQuery code into a directive and then ‘decorate’ your DOM with that functionality. The upside is that your code now becomes very portable and you can apply it to more than one element without having to go down the path of writing a query for every element you want to target.

Another upside is that because of the way that AngularJS compiles directives you never have to worry about dynamic elements getting event handlers. This is because the element parameter is always a jQuery object to start out with.

Resources

The Code Example:

https://github.com/simpulton/angular-designers

Shane Mielke’s Portfolio [He really is one of my favorite designers]:

http://www.shanemielke.com/work.php

AngularJS Directive Guide [Which I still reference often]:

http://docs.angularjs.org/guide/directive