Posted on by & filed under Content - Highlights and Reviews, Programming & Development, Tech.

code A guest post by Christopher Hiller, the author of Developing an AngularJS Edge and a Software Architect for Decipher, Inc. He enjoys gaming, coding, and gleaming the cube. He can be reached on GitHub or as @misterhiller on Twitter.

Before we get started on refactoring in AngularJS, I want to make sure you’ve seen the two previous posts in this series: 13 Steps to AngularJS Modularization and Writing Tests and Stomping Bugs in AngularJS. In this final part of the series, I’ll discuss how to get your hands filthy with the code.


Do any of the following sound familiar?

  • It’s hard to debug your view, because you have no idea where that Scope member is coming from
  • When you inspect a Scope, you double-take because you thought it was the window object
  • You at some point needed to access a child Scope member from a parent Scope, so you either either a) used $broadcast/$on to call it, or b) just moved the member into the parent Scope
  • It’s unclear what is happening after any given user action, because there are umpteen-hundred events being emitted or broadcast
  • There’s at least one service that is 1,000 lines long and is full of just random settings
  • You either have one entry point into $http, or $http calls are scattered about controllers

These are all mistakes, and they are easy mistakes to make. The solution to all of these problems is the same: refactor.

Why Refactor?

Refactoring is often not popular among product stakeholders because what happens is that significant resources are consumed, and from an outside perspective, nothing much has changed. The developer will probably fix some bugs and introduce others. Rarely does anyone get a fancy new feature to show off. The selling point of refactoring is that it is an up-front expense with long-term gain. If you spend time refactoring now, in the future, feature development will take a fraction of the time than it would without the refactor. Let’s discuss all of these issues and find some solutions.

Complex Controller Hierarchies

You have many nested controllers, and there’s an over-reliance on Scope hierarchy. In the chaos, however, patterns are recognizable, and I can offer some guidelines.


with controller A:

and controller B:

Scope member foo should move from controller A to controller B, because controller A‘s view does not use foo.

Controllers provide logic and data to the view. If a controller’s view does not use a Scope member, that Scope member should not be in the controller’s Scope.

It can be difficult to extract functions from the parent controller. For example:

Function foo() should not live in controller A, and then neither should variable f. But, if we move f, the baz() function will fail with a ReferenceError. How should we solve this? Simply, use a service or factory:

This buys you added testability (by separation of concerns) and a cleaner scope. I’ve found that if I use services wherever appropriate, the result is a very well-organized and testable application. So, for functions that don’t interact with a Scope, see if they belong in a service.

If you have a function in a controller’s Scope, however, and not used elsewhere that does not interact with the Scope itself:

  • You’re going to want to make that function testable
  • Creating a one-off service, factory or value just for this function seems silly
  • The function still doesn’t belong in a Scope

Your choices are fairly limited. The solutions I’ve found are not profoundly elegant, but they work:

You’re basically putting a static function on the controller. This provides exposure for testing, keeps your function out of the Scope, and doesn’t unnecessarily create a service. Unfortunately, you lose access to a Scope and injected services, unless you call your method via $injector.invoke():

$location will automatically be injected by invoke().

Another way is to simply use this:

This achieves the same goals without having to leverage $injector, but with the alternative drawback: if you are using the “controller as” syntax, you wind up with your baz() function in the Scope anyway.

Using this in Scope member functions

The caveat with this in Scope member functions is that the value of this varies. Here, this refers to the Scope, not the controller. If a child calls a function in its parent’s Scope, this refers to the child’s Scope. Since the child inherits from the parent anyway, your code will likely still work, but it can be particularly confusing for those new to AngularJS or JavaScript.

The Scope hierarchy is just one of AngularJS’ tools. Generally, I’ve found that using this tool within nested controllers causes confusion, night sweats, and eventually certain doom. A good place to use inheritance is within directives.

Consider Directives

You can probably turn some of your controllers into isolate Scope directives. This works best for smaller controllers that are potentially reusable, that rely little on their parent Scopes, and whose child Scopes (if any) do not use inheritance.

To get this done:

  1. Find your target controller
  2. Extract its view into a partial if it isn’t already
  3. Create a .js file for the new directive
  4. Move directive .js and partial .html into an appropriate module directory (see the post about modularization) if necessary
  5. Use this template (where previously you had FooCtrl, you now have foo):

    Now, the markup, given baz and quux in the old controller’s parent Scope:

    If there are too many attributes to pass, you can omit scope from the DDO or give it a value of true. Alternatively, you could create a single options attribute, and stuff everything from the parent Scope into that.

    This technique is easier to apply when writing an app from the ground up, because it affects your app design; remember it for your next app and apply it where appropriate.

    Don’t create a directive to create a directive. If your controller is reusable and/or fairly distinguished from neighboring Scopes, consider it.

    The World’s Largest Ball of Events

    If you try to unwind the flow of control through your $broadcast()/$emit()/$on() and keep losing your place, you have too many events*. Events (or “PubSub” or whathaveyou) are tools to use when you either don’t know or don’t care what’s listening to the event. In other words, if you expect that emitting your event calls function mayo() in SandwichCtrl, you’ve misused this pattern. This pattern is especially handy to use in libraries, so applications can listen and take appropriate action.

    Find your events. Make a sequence diagram if you need to. Because any component can use $on(), there are simply too many permutations to address, but I can offer some guidelines:

    • Be especially wary of $broadcast()s whose sole purpose is to call a child Scope member function from a parent Scope. These are potentially the most troublesome; they are difficult to refactor and one of the more egregious misuses of this pattern. See “Complex Controller Hierarchies” above.
    • If you’re broadcasting from $rootScope, see if you can reign it in a little to a more appropriate context.
    • $rootScope is the AngularJS equivalent of the window object–the less stuff in $rootScope, the better.
    • If you’re $emit()ing on $rootScope, I’m sorry.
    • If you have a raucous crowd of emitters and broadcasters, and few listeners, you may have overengineered. Delete.
    • In the general case, try to use a service, factory, or communicate between directives. Call functions explicitly. You could even change routes if it makes sense!

    The object here is not to annihilate all events. The flow between your emitters and listeners should be transparent, and ideally you won’t have many chains.


    This concludes the three-part series on maintaining large AngularJS applications. Organize your code, write your tests, and refactor–three pills you can take to ease your maintenance headaches.

    For more details about AngularJS, see the resources below from Safari Books Online.

    Not a subscriber? Sign up for a free trial.

    Safari Books Online has the content you need

    Developing an AngularJS Edge is intended for intermediate JavaScript programmers. No attempt has been made to explain the JavaScript syntax used (except in the cases where AngularJS may introduce a peculiarity), nor do we explain concepts such as closures, function chaining, callbacks, or other common patterns. What we do explain are basic AngularJS concepts, components, and their applications. We provide examples along the way, answer questions, and correct common misconceptions. Together, we’ll build a working single-page weblog application using AngularJS, which will help you become proficient with using AngularJS to go out and create your own applications.
    Develop smaller, lighter web apps that are simple to create and easy to test, extend, and maintain as they grow. AngularJS is a hands-on guide that introduces you to AngularJS, the open source JavaScript framework that uses Model–view–controller (MVC) architecture, data binding, client-side templates, and dependency injection to create a much-needed structure for building web applications.
    Instant AngularJS Starter is designed to get you ramped up on AngularJS as quickly and efficiently as possible. By the end of this book, you’ll possess all of the knowledge you need to make full-featured, real-life applications with AngularJS. The code samples are reusable, and specifically intended to give you a head start on your next project. This book will transform your curiosity about AngularJS into a set of production-ready AngularJS skills, through a broad overview of the framework and deep dives into its key features.

Tags: AngularJS, Controller Hierarchies, events, Javascript, refactor, refactoring, Scope, test,

One Response to “Get Your Hands Dirty Refactoring in AngularJS”

  1. jkl

    Nice article, but what’s with the & l t ; and & g t ; in the snippets?