Wednesday, November 26, 2014

The Top 5 Mistakes AngularJS Developers Make Part 1: Relying on $scope

Although AngularJS is an extraordinarily popular framework, there is plenty of discussion and controversy over whether or not it truly adds value to projects. Having witnessed its value firsthand as I described in my recent post, Angular from a Different Angle, I believe it can be a powerful tool when used correctly. Voltaire said, “With great power comes great responsibility.” A tool like Angular can be easily abused. This series is designed to help you avoid common traps and pitfalls before they become a problem.

The top five mistakes I see people make are:

  1. Heavy reliance on $scope (not using controller as) 
  2. Abusing $watch
  3. Overusing $broadcast and $emit
  4. Hacking the DOM
  5. Failing to Test

In this series I’ll cover examples of both how these items are abused and my suggested “better practice.” Let’s get started with the first mistake.

Relying on $scope (Not Using Controller As)

The canonical Angular tutorial inevitably introduces controllers and forces them to take on a dependency to $scope, like this:

<div ng-app="myApp">
    <div ng-controller="badCtrl">
        <input placeholder="Type your name" ng-model="name" />
        <button ng-click="greetMe()" ng-disabled="notValid()">Greet Me!</button>
    </div>
</
div>
(function () {
    var app = angular.module('myApp', []);
    function BadController($scope) {
        $scope.notValid = function () {
            var bad = !!$scope.name;
            return !bad || $scope.name.length < 1;
        };
        $scope.greetMe = function () {
            if ($scope.notValid()) {
                return;
            }
            alert('Hello, ' + $scope.name);
            $scope.name = '';
        };
    }

    app.controller('badCtrl', BadController);
    
})();

A controller in Angular is really what I would refer to as a “view model.” In the diagram below, just replace “XAML” with “HTML” to visualize the relationship.

main[1]

A controller in the traditional sense marshals activity between the application model and view but typically does so in a more active fashion. A view model, on the other hand, simply exposes properties and functions for data-binding. I like this approach because it allows your view models to simply exist as “state bags” – they may interact with services to grab lists or other items but in the end they just expose it. You can then bind to that data and represent it however you like.

Taking on the dependency to $scope does two things. First, it requires the controller to be aware that it is participating in data-binding when it doesn’t have to. It certainly simplifies things when you can just expose a list as a list and a selected item as a property and test that in isolation without worrying about what the glue looks like. The controller defined earlier really just exists as a proxy with the sole purpose of passing setup onto the $scope. Why take on that extra work?

Second, it complicates the testing story because now you have to ensure that a $scope is created and passed in to do something. The controller really becomes a facade to the $scope so you end up with a lot of code marshalling values between the two.

(queue Dr. Evil voice … “If only there were a way for the controller to BE the $scope…”)

Wait! There is! Using the controller as syntax enables you to treat and test controllers as standalone plain old JavaScript objects (POJOs). Consider this example:

<div ng-controller="goodCtrl as ctrl">
    <input placeholder="Type your name" 
            ng-model="ctrl.name" />
    <button ng-click="ctrl.greetMe()" 
            ng-disabled="ctrl.notValid()">Greet Me! </button>
</
div>
(function () {
    var app = angular.module('myApp', []);
    function GoodController() {
    }
    angular.extend(GoodController.prototype, {
        notValid: function () {
            var bad = !!this.name;
            return !bad || name.length < 1;
        },
        greetMe: function () {
            if (this.notValid()) {
                return;
            }
            alert('Hello, ' + this.name);
            this.name = '';
        }
    });
    app.controller('goodCtrl', GoodController);
})();

Although it uses angular.extend, the controller could just as easily have been defined via the constructor function prototype. This makes it a pure JavaScript object. It has no dependencies, and why should it? We haven’t written a controller complicated enough to warrant dependencies yet. $scope just muddies the waters.

I made a fiddle to demonstrate the $scope vs. “controller as” approaches side-by-side.

In fact, if you are taking a test-driven development (TDD) approach, you don’t even have to worry about Angular at first. You can create your controller as a POJO and write plenty of tests, then introduce it as a controller to the application. This provides more flexibility and less reliance on what version is running or even what the UI looks like.

An added bonus is that you can alias the controller in your code so that you either segregate it per section by name, or give it a common name like ctrl to make it easier to build boilerplate HTML code. This syntax is also available from your routes.

Of course, the first response I typically get when I mention not using $scope is “What about watches?” My reply is, “What about them?” Angular does a lot of watching for you, so the real question is whether you really need those watches, or if there is a better way. There may be, and that’s what I’ll cover in the next part of this series.

signature[1]

Wednesday, October 22, 2014

A Different Angle: What is AngularJS?

This post covers my presentation, AngularJS from a Different Angle, that I presented to the Atlanta JavaScript Meetup group on October 20th, 2014. This was just over a week after the Atlanta Code Camp, when I presented Let’s Build an Angular App! Many of the attendees are local and might have attended both events so I wanted to make something unique.

600_423950092

It was then I realized that most Angular articles and presentations I see tend to walk through the Angular API. Did you know Angular has a factory? What about a service? It does dependency injection, and oh, let me tell you about the data-binding! Although that can be useful, what does it look like when you take a step back and view it from a higher angle? In other words, if I’m in charge of an upcoming project and am putting together my toolbox, how would I look at these frameworks?

Even before looking at features I’d probably want to know about real world use cases. How many times have you read a question posted that went something like, “Show me the money!” (Err, I know, it’s not really a question). In other words, what real world apps have been implemented with Angular? It’s one thing to point to a set of websites and say, “Look, that’s Angular.” It’s quite another to talk to someone on a team who built out an enterprise production app.

I’m a person that has done that several times and am happy to share the details. The largest app is one I share often because it really introduced me to the power and flexibility of Angular, and it went something like this:

  • 25 Developers at peak development
  • Globally distributed team with remote workers distributed across all international time zones (except perhaps a few bands that cross nothing but ocean)
  • 80,000+ lines of TypeScript code that probably generated to a lot more JavaScript code (but after minification/uglification I’m sad to report the codebase had only one single line of code)
  • Several hundred Angular components including directives, filters, controllers, services, etc.
  • 3 years of development (although Angular was introduced later into the cycle, which is important because it gave us insights into how it positively impacted the team)

About 6 months into the project we held a retrospective and decided to go with AngularJS and TypeScript based on a POC. After based on velocity and code quality we estimate between 2 – 4x speed of delivery of accepted code compared to before, and the team attributes a lot of that to Angular.

But What Is It?

If you want to look at it from a different angle, I believe Angular provides five fundamental services in an approach that considers testing a first-class citizen.

whatisnagular

  • Declarative expressions
  • Glue
  • A container
  • Templates (not just talking UI templates)
  • Tools

To learn more, watch the video:

 

And follow along with the slide deck (links to code samples are on the last slide):

Thanks!

Sunday, October 12, 2014

Let's Build an AngularJS App!

This weekend I had the pleasure of attending the Atlanta Code Camp. It was a fantastic venue with sold out attendance and a variety of speakers covering cutting edge topics. I always try to submit a variety of topics but due to popularity, AngularJS won again! I've watched many talks that break down various facets of Angular and even some live coding demonstrations, but realized there haven't been many that cover building an actual, functional app with unit tests.

I structured the talk so that I could easily go from start to finish in stages. In the PowerPoint deck you'll see I have actual git checkout commands that reference the various commits. This will enable you to roll forward to each step after you've cloned the repository. The result is a responsive health calculator app that scales well to a variety of page sizes, has built-in validations for inputs and provides you with basal metabolic rate (BMR), body mass index (BMI), and target heart rate zones (THR). The app was developed using a test-driven (TDD) approach with a total of 83 specifications. The GitHub repository has full source and instructions.

Here is the deck. I hope you enjoy!




Jeremy Likness