Sunday, July 27, 2014

Using AngularJS to Extend Your Code Quality

The AngularJS API provides a function named extend that can help improve your code quality and efficiency. I always look for ways to improve quality, increase efficiency, reduce risk and eliminate ritual and ceremony when I am developing software. Perhaps the simplest way to express this is the DRY principle (Don’t Repeat Yourself). I prefer a refactoring-driven approach to this principle. Instead of trying to anticipate what might be needed in a framework, I simply evolve it and refactor when I see an opportunity to improvement. Oftentimes Angular’s extend function is a part of that refactoring.

Assume I am writing a page that allows the user to click two buttons to produce a list of categories and products. Here is a screenshot with the categories loaded and the products waiting for the user to request them.

image

The source for data is exposed via the example API at OData.org. To encapsulate the call for categories, I create a component and register it with Angular that looks like this:

function CategoriesService($http, $q) {
     this.$http = $http;
     this.$q = $q; } 




CategoriesService.prototype.get = function () {
     var deferral = this.$q.defer();
     this.$http.get('http://services.odata.org/V4/OData/OData.svc/')
         .success(function (response) {
             deferral.resolve(response.value);
         })
         .error(function (err) {
             deferral.reject(err);
         });
     return deferral.promise; }; app.service('categories', CategoriesService);

Next, I move on to products. It turns out that the products service looks almost identical to the categories service! I don’t want to repeat myself so it’s time to refactor the code to take advantage of the principle of inheritance. I encapsulate the base functionality for dealing with the service in a base class, then inherit from that and specify what’s unique between products and categories. The base class looks like this:

var baseOData = {
     $http: {},
     $q: {},
     baseUrl: 'http://services.odata.org/V4/OData/OData.svc/',
     entity: '',
     get: function () {
         var defer = this.$q.defer();
         this.$http.get(this.baseUrl + this.entity)
             .success(function (response) {
                 defer.resolve(response.value);
             })
             .error(function (err) {
                 defer.reject(err);
             });
         return defer.promise;
     } };

Notice I’ve captured everything that is repeated: the base portion of the URL and the wrapper that handles the promise so the result is returned and the consuming class doesn’t have to understand how the collection is implemented in the API. The only difference I found between the categories and products is the name of the entity specified in the URL, so I expose that with a property on the base class that can be overridden by the service implementation. Using this base class I implement the category service like this:

function CategoriesService($http, $q) {
     this.$http = $http;
     this.$q = $q;
     this.entity = 'Categories'; } angular.extend(CategoriesService.prototype, baseOData); app.service('categories', CategoriesService);

The shell for the categories service simply sets up the dependencies and registers the entity because the base class holds all of the common functionality. The call to extend automatically applies the properties and functions from the base definition to the category service. Notice that I am extending the prototype; this will ensure that the properties and functions are part of any instance that is created. Angular will also bind the properties and functions so this refers to the instance itself.

The products service is then implemented the same way with a different entity specified. Although I could provide a service that takes in the entity as a parameter and returns the promise (even less code), I may want to have specific properties or methods that are unique to the category and/or product implementation. I really don’t know yet so I keep them as separate components and will refactor them down to a single service if the pattern doesn’t change.

You can call extend multiple times or pass a collection of objects. This enables your components to inherit from multiple “base classes.” Another way to look at it is that you can define behaviors and apply those behaviors to the class.

I prefer the “controller as” syntax for my controller definitions. In this example the controller takes a dependency on the product and category service and exposes methods to request them that are bound to buttons. The initial implementation looked like this:

function Controller(products, categories) {
     this.productService = products;
     this.categoryService = categories;
     this.products = [];
     this.categories = []; } Controller.prototype.getCategories = function () {
     var _this = this;
     this.categoryService.get().then(function (result) {
         _this.categories = result;
     }); }; Controller.prototype.getProducts = function () {
     var _this = this;
     this.productService.get().then(function (result) {
         _this.products = result;
     }); }; app.controller('exampleCtrl', Controller);

Wouldn’t it be nice if to encapsulate the controller functionality in a single definition? Actually, that is possible! Using extend I simplified the declaration for my controller by combining the functions into a single object definition. I removed the initialization of the product and categories list from the constructor and moved them into a consolidated definition that looks like this:

angular.extend(Controller.prototype, {
     products: [],
     categories: [],
     getCategories: function () {
         var _this = this;
         this.categoryService.get().then(function (result) {
             _this.categories = result;
         });
     },
     getProducts: function () {
         var _this = this;
         this.productService.get().then(function (result) {
             _this.products = result;
         });
     } });

This convention makes it easier to group related functionality together and ensure there is a consistent implementation of this. The implementation is very similar to the way that TypeScript handles inheritance.

As you can see, although the documentation for extend is quite simple, the functionality can be quite powerful. View the source code and full working example here.

Sunday, July 20, 2014

AngularJS Debugging and Performance

Just over a week ago an Angular project went live after several years of development. Our team peaked at over 25 developers distributed around the world. The source ended up at over 80,000 lines of TypeScript code (although I jokingly note this ends up as just one line of minified JavaScript) and includes hundreds of controllers, services, views, etc. You don’t get that far in an enterprise app without learning a thing or two about debugging and performance.

I just released my video “AngularJS: Debugging and Performance” as the 12th lesson in my course, Mastering AngularJS. This course covers everything you need to know to build business apps in Angular. Topics start out with fundamentals that provides an end-to-end overview, followed by a deep dive into scope and the digest loop. Learn about advanced filters, how dependency injection works, and what the built-in Angular services are. Lessons cover consuming web services from Angular (using both $http and ngResource), handling routing with ngRoute and ui-router, fundamentals of directives and advanced directives. I cover testing using Jasmine and this latest video is all about debugging and performance.

The debugging and performance lesson starts by covering some of the built-in Angular services like $exceptionHandler and $log, and how to leverage the JavaScript debugger key word. I then dive into how to troubleshoot Angular applications by inspecting the HTML DOM and using that to dive into source code and unravel the HTML nodes generated by templates. I cover the Chrome Batarang extension and then go into using Chrome Developer Tools to troubleshoot a memory leak. Learn how to use the Zone library to instrument your apps, how to avoid the overhead of extra watches when data-binding to render static data, and how to deal with extremely long (one million records or more) lists on the client. I include tips for using the right directives to condition rendering of the DOM, how to minimize overhead of watches, and how to take advantage of lazy-loading or instantiation of new components “on the fly.”

The course includes full access to working examples and source code. If you are working with Angular, I know you will want to check this lesson out.

Saturday, July 19, 2014

AngularJS Quick Tip: Counting Watches

Sometimes for troubleshooting purposes it is important to understand how many watches exist in an Angular app. You may be surprised to find that in certain scenarios, you are generating many more watches than you anticipate. For example, simply using ng-repeat on a long list will create a watch for every element unless you use a library like bindonce. Fortunately, because Angular is tightly coupled to the HTML DOM, it is not difficult to hook in and look under the hood.

To make it even easier, I created a simple module called jlikness.watch that contains a single directive and service. To use the module, you simply place a directive at the topmost element in your app you want to count watches from, then reference the service and call the countWatches() method any time you wish to get an updated count.

The main logic simply checks to see if an element has an associated scope, and if it does, uses Angular’s internal $$watchers collection to add the count.

if (element.scope()) {
    _this.watchCount += element.scope().$$watchers.length;
}

The function then recursively calls itself for each child of the element being inspected.

angular.forEach(element.children(), function (child) {
    iterate(angular.element(child));
});

This naive implementation will give a count, but because scope() walks up the DOM hierarchy to find the first parent with a valid scope the count may be off. The code can duplicate counts because children of the element may point to the same parent scope. The fix is to track the scopes by their Angular $id. You can see that code implemented in the latest source at the jlikness.watch repository.

The directive is used to pass the root element to the service as a starting point for the recursive count.

w.directive('jlWatch', ['jlWatchService', function (ws) {
    return {
        restrict: 'A',
        link: function (scope, elem) {
            ws.register(elem);   
        }
    };
}]);

Using the directive and service is very straightforward, as shown in this example. Click the refresh button to see the number of watches generated for even a fairly small app.

(function (app) {
    app.run(['$rootScope', 'jlWatchService', function ($rootScope, ws) {
        angular.extend($rootScope, {
            title: 'Angular Watchers',
            watchCount: 0,
            refreshWatches: function () {
                this.watchCount = ws.countWatches();
            }
        });       
    }]);
})(angular.module('myApp', ['jlikness.watch']));

That’s it – plain and simple, but very eye-opening when you start dealing with complex pages and long lists.