Videos from NDC Oslo 2014

Monday, June 16, 2014 by K. Scott Allen
6 comments

NDC Oslo featured some fantastic content, and most of the talks are uploaded to the NDC vimeo channel.

In addition to a 2 day AngularJS workshop, I presented one session on building directives for AngularJS.

image

Also a session on using NodeJS tools for front end development (npm, Bower, Grunt, Gulp, Treceur, and more).

NodeJS Tools

I hope you like them!

Model Options and Pristine Forms In AngularJS

Tuesday, June 10, 2014 by K. Scott Allen
5 comments

Here is a plunk that demonstrates how to reset an Angular form. The form itself will display any element with a dirty flag using a thick red border. The ngModel and ngForm directives automatically add the ng-dirty class to elements with a dirty flag, and the CSS rule applied is like so:

.ng-dirty {
    border: red 5px solid;
}

Notice how typing into an input not only makes the input dirty, but also makes the form itself dirty (a double border).

Dirty AngularJS Form

You might also notice when typing into the first input how the dirty flag takes a couple seconds to appear. The delay is because of the new ngModelOptions directive in 1.3. With ngModelOptions you can specify the events required to push values into the model (perhaps using the blur event instead of the keypress event), and also debounce the data binding by specifying a number of quiet milliseconds to elapse before pushing data. The example plunk is waiting for 2,000 milliseconds.

<form name="editUserForm">

    <input type="text" ng-model="user.firstName" ng-model-options="{debounce:1000}"/>
    <input type="text" ng-model="user.lastName"/>
    <input type="submit" value="Submit"/>
    <input type="button" value="Reset" ng-click="reset()"/>

</form>

The reset button will set the form back into a pristine state using $setPristine. $setPristine recursively sets all the controls inside the form to a pristine state, too. It’s up to the application logic to replace the data, perhaps by making a copy of the original form data, as shown below.

$scope.user = {
    firstName: "Scott",
    lastName: "Allen"
};

$scope.originalUser = angular.copy($scope.user);

$scope.reset = function(){
    $scope.user = angular.copy($scope.originalUser);
    $scope.editUserForm.$setPristine();
};

Quite a bit of power from a minimum amount of code.

AngularJS: Get Started Video Course

Monday, June 9, 2014 by K. Scott Allen
10 comments

AnguarJS: Get Started is now available to Pluralsight subscribers.

This video course is a small but focused subset of my full Angular class. The course assumes you know a bit about HTML, CSS, and JavaScript, but want to start from the beginning and learn about the core pieces of Angular, like how to work with controllers, services, and directives.

In the video we’ll build a “GitHub Viewer” application to search GitHub users and repositories.

AngularJS and GutHub

I hope you like it!

Building Multiple Filters with Lo-Dash and AngularJS

Thursday, May 29, 2014 by K. Scott Allen
4 comments

You can try the code in this post yourself.

Imagine we have the following movie data returned by an API call from the server.

var movies = [
    { title: "Godzilla", genre:"Action", released: 2014},
    { title: "Neighbors", genre: "Comedy", released: 2014},
    { title: "Into The Woods", genre: "Musical", released: 2014},
    . . .
];

Now, we need to display the data and allow the user to filter on genre, release year, or both. First, we’ll use lodash to build a unique list of available options for these attributes, and then store the options in scope.

app.controller("mainController", function($scope, movieData) {

    $scope.movies = movieData.getAll();

    $scope.genres = _.chain($scope.movies).pluck("genre").uniq().sortBy().value();
    $scope.years = _.chain($scope.movies).pluck("released").uniq().sortBy().value();

    $scope.clearFilters = function(){
        $scope.selectedGenre =  undefined;
        $scope.selectedYear = undefined;
    };

});

In the view we can build the filtering selects and a table using ngOptions and ngRepeat.

<div ng-controller="mainController">

  <select ng-model="selectedGenre" ng-options="genre for genre in genres"></select>
  <select ng-model="selectedYear" ng-options="year for year in years"></select>
  <button ng-click="clearFilters()">Clear</button>

  <table class="table">
    <thead>. . . </thead>
    <tbody>
      <tr ng-repeat="movie in movies |
            filter:{ genre: selectedGenre, released:selectedYear }">
        <td>{{movie.title}}</td>
        <td>{{movie.genre}}</td>
        <td>{{movie.released}}</td>
      </tr>
    </tbody>
  </table>

</div>

Notice how the filter filter in Angular understands how to take an object expression and apply predicates to the specified attributes.

Compile, Pre, and Post Linking in AngularJS

Wednesday, May 28, 2014 by K. Scott Allen
12 comments

Explanations of the compile and link functions in an AngularJS directive don’t often come with examples. Let’s look at a directive named simple which appears in the following markup. You can also play along  in this plunk. Open the browser’s developer tools to see the logging output. 

<div ng-repeat="i in [0,1,2]">
    <simple>
        <div>Inner content</div>
    </simple>
</div>

Notice the directive appears once inside an ng-repeat and will need to render three times. The directive also contains some inner content.

What we want to focus on is how and when the various directive functions execute, as well as the arguments to the compile and linking functions.

To see what happens we’ll use the following shell of a directive definition.

app.directive("simple", function(){
   return {
     restrict: "EA",
     transclude:true,
     template:"<div>{{label}}<div ng-transclude></div></div>",

     compile: function(element, attributes){

         return {
             pre: function(scope, element, attributes, controller, transcludeFn){

             },
             post: function(scope, element, attributes, controller, transcludeFn){

             }
         }
     },
     controller: function($scope){

     }
   };
});

Compile Executes Once

Element in Angular Compile FunctionThe first function to execute in the simple directive during view rendering will be the compile function. The compile function will receive the simple element as a jqLite reference, and the element contents will look like the content in the picture to the right. 

Notice how Angular has already added the directive template, but has not performed any transclusion or setup the data binding.

At this point it is safe for the code inside the compile function to manipulate the element, however it is not a place where you want the code to wire up event handlers. The element passed to compile in this scenario will be an element that the framework clones three times because we are working inside an ngRepeat. It will be the clones of this element the framework places into the DOM, and these clones are not available until the linking functions start to run. The idea behind the compilation step is to allow for one time DOM manipulation before the cloning – a performance optimization.

This compile function in the sample above returns an object with the pre and post linking functions. However, many times we don’t need to hook into the compilation phase, so we can have a link function instead of a compile function.

app.directive("simple", function(){
    return {
       //... 
        link: function(scope, element, attributes){

        },
        controller: function($scope, $element){

        }
    };
});

A link function will behave like the post-link function described below.

Loop Three Times

Since the ngRepeat requires three copies of simple, we will now execute the following functions once for each instance. The order is controller, pre, then post.

Controller Function Executes

The first function to execute for each instance is the controller function. It is here where the code can initialize a scope object as any good controller function will do.

Note the controller can also take an $element argument and receive a reference to the simple element clone that will appear in the DOM.

The element will look just like the element in the previous picture because the framework hasn’t performed the transclusion or setup data binding, but it is the element that will live in the DOM, unlike the element reference in compile.

However, we try to keep controllers from referencing elements directly. You generally want to limit direct element interaction to the post link function.

Pre-link Executes

Element In Angular Pre LinkBy the time we reach the pre-link function (the function attached to the pre property of the object returned from compile), we’ll have both a scope initialized by the controller function, and a reference to a real element that will appear in the DOM.

However, we still don’t have transcluded content and the template isn’t linked to the scope because the bindings aren’t setup.

The pre link function is only useful in a couple special scenarios, which is why you can return a function from compile instead of an object and the function will be considered by the framework as the post link function.

Post-link Executes

Element in AngularJS Post LinkPost link is the last function to execute. Now the transclusion is complete, the template is linked to a scope, and the view will update with data bound values after the next digest cycle .

In post-link it is safe to manipulate the DOM, attach event handlers, inspect child elements, and setup observations on attributes and watches on the scope.

Summary

Directives have many mysterious features when you first come across them, but with some time and experiments like these you can at least figure out the working pieces. As always, the harder part is knowing how to apply this knowledge to the real components you need to build. More on that in the future.

Debugging AngularJS Data Binding

Tuesday, May 27, 2014 by K. Scott Allen
1 comment

One common question I’ve gotten about AngularJS revolves around the debugging of binding expressions like {{ message }}. How does one track down expressions that aren’t working?

There are two approaches I can recommend. One approach is a tool, the other approach is a service decorator.

Batarang

Batarang is a fairly well known Chrome extension. Once loaded, the extension can show you the contents of scope objects, as well as profiling and performance information.

image

For some problems Batarang requires too many mouse clicks, that’s when I like to use a simple service decorator.

Decorating $interpolate

In Angular, the $interpolate service is responsible for working with binding expression. The service returns a function you can invoke against a scope object to produce an interpolated string. The function is known as an interpolation function.

As an example, the following code will log “HELLO!” to the console.

app.run(function($interpolate){
    var fn = $interpolate("{{message | uppercase}}");
    var result = fn({message:"Hello!"});
    console.log(result);
});

The interpolation function is forgiving. For most scenarios the forgiveness is good, because we can write binding expressions in a template without worrying about null or undefined values.

As an example, the following code does not throw an exception or give any indication of an error even though message is misspelled as massage in the binding expression.

app.run(function($interpolate){
    var fn = $interpolate("{{massage.length}}");
    var result = fn({message:"Hello!"});
    console.log(result);
});

Instead of an error, the interpolation function yields an empty string. These are the types of cases we might want to know about. Unfortunately, the functions interpreting and executing the binding expressions are hidden and have many special case branches. However, we can decorate the $interpolate service and wrap the interpolation functions it produces.

app.config(function($provide){
    $provide.decorator("$interpolate", function($delegate){

        var interpolateWrap = function(){
            var interpolationFn = $delegate.apply(this, arguments);
            if(interpolationFn) {
                return interpolationFnWrap(interpolationFn, arguments);
            }
        };

        var interpolationFnWrap = function(interpolationFn, interpolationArgs){
            return function(){
                var result = interpolationFn.apply(this, arguments);
                var log = result ? console.log : console.warn;
                log.call(console, "interpolation of  " + interpolationArgs[0].trim(), 
                                  ":", result.trim());
                return result;
            };
        };

        angular.extend(interpolateWrap, $delegate);
        return interpolateWrap;

    });
});

The wrapping function will log every execution that produces a string and warn about every interpolation that produces a false looking empty string (which is what happens if there is a type or undefined member on scope).

Now let’s see what happens with the following markup in a template. Note that foobar is not a property on scope and represents a bad binding expression we want to catch.

<span>{{ message }}</span>
<span>{{1 + 2}}</span>
<span>{{getMessage() | uppercase}}</span>
<span>{{foobar}}</span>

<div ng-repeat="i in [0,1,2,3]">
    {{i * 2}}
</div>

The output in the developer tools looks like the following.

Warning On Bad Angular Bindings

Now we can see all the interpolation activity on a page, and the activity producing empty strings will stand out. You probably don’t want to ship with an active decorator like the one in this post, but it can make some debugging chores quick and easy.

Using Resolve In AngularJS Routes

Tuesday, May 20, 2014 by K. Scott Allen
11 comments

In a previous post about testing I mentioned that route resolves can make authoring unit tests for a controller easier. Resolves can also help the user experience.

A resolve is a property you can attach to a route in both ngRoute and the more robust UI router. A resolve contains one or more promises that must resolve successfully before the route will change. This means you can wait for data to become available before showing a view, and simplify the initialization of the model inside a controller because the initial data is given to the controller instead of the controller needing to go out and fetch the data.

As an example, let’s use the following simple service which uses $q to simulate the async work required to fetch some data.

app.factory("messageService", function($q){
    return {
        getMessage: function(){
            return $q.when("Hello World!");
        }
    };
});

And now the routing configuration that will use the service in a resolve.

$routeProvider
    .when("/news", {
        templateUrl: "newsView.html",
        controller: "newsController",
        resolve: {
            message: function(messageService){
                return messageService.getMessage();
        }
    }
})

Resolve is a property on the routing configuration, and each property on resolve can be an injectable function (meaning it can ask for service dependencies). The function should return a promise.

When the promise completes successfully, the resolve property (message in this scenario) is available to inject into a controller function. In other words, all a controller needs to do to grab data gathered during resolve is to ask for the data using the same name as the resolve property (message).

app.controller("newsController", function (message) {
    $scope.message = message;
});

You can work with multiple resolve properties. As an example, let’s introduce a 2nd service. Unlike the messageService, this service is a little bit slow.

app.factory("greetingService", function($q, $timeout){
   return {
       getGreeting: function(){
           var deferred = $q.defer();
           $timeout(function(){
               deferred.resolve("Allo!");
           },2000);
           return deferred.promise;
       }
   }
});

Now the resolve in the routing configuration has two promise producing functions.

.when("/news", {
    templateUrl: "newsView.html",
    controller: "newsController",
    resolve: {
        message: function(messageService){
            return messageService.getMessage();
        },
        greeting: function(greetingService){
            return greetingService.getGreeting();
        }
    }
})

And the associated controller can ask for both message and greeting.

app.controller("newsController", function ($scope, message, greeting) {
    $scope.message = message;
    $scope.greeting = greeting;
});

Composing Resolve

Although there are benefits to moving code out of a controller, there are also drawbacks to having code inside the route definitions. For controllers that require a complicated setup I like to use a small service dedicated to providing resolve features for a controller. The service relies heavily on promise composition and might look like the following.

app.factory("newsControllerInitialData", function(messageService, greetingService, $q) {
    return function() {
        var message = messageService.getMessage();
        var greeting = greetingService.getGreeting();

        return $q.all([message, greeting]).then(function(results){
            return {
                message: results[0],
                greeting: results[1]
            };
        });
    }
});

Not only is the code inside a service easier to test than the code inside a route definition, but the route definitions are also easier to read.

.when("/news", {
    templateUrl: "newsView.html",
    controller: "newsController",
    resolve: {
        initialData: function(newsControllerInitialData){
            return newsControllerInitialData();
        }
    }
})

And the controller is also easy.

app.controller("newsController", function ($scope, initialData) {
    $scope.message = initialData.message;
    $scope.greeting = initialData.greeting;
});

One of the keys to all of this working is $q.all, which is a beautiful way to compose promises and run requests in parallel.

by K. Scott Allen K.Scott Allen
My Pluralsight Courses
The Podcast!