Extending AngularJS Controllers Using the Mixin Pattern

In this post we are going to look at extending the functionality of AngularJS controllers using the mixin pattern.  While developing large scale applications it is desirable to break out general functionality into base controllers that can be used across multiple controllers. In addition, the mixin pattern provides a great deal of flexibility to not only inherit instance methods and properties, but $scope properties and methods as well.  Examples used in this post can be downloaded from GitHub.

A quick look at prototypal inheritance

A great way to extend the functionality of JavaScript objects is to use prototypal inheritance.  Lets begin with a simple example using cats and dogs, and create a base class that describes common properties across all animals.  Animals vocalize to one extent or another so lets start with defining the following base Animal class:

Since dogs vocalize by barking, we can inherit from Animal using the following declaration:

And cats meow:

Now we can instantiate Dog and Cat and invoke the vocalize method:

Lets move to AngularJS controllers. Suppose we have a DogController, and we want it to inherit from Animal as we did above. It would be tempting to do something like this thinking our controller has the instance method, “vocalize”:

Sadly we would run into, “TypeError… has no method ‘vocalize’”, once our $scope.bark() gets invoked.  The reason for this error is simple.  Angular controllers do not get instantiated, and without an object instance, no instance methods get inherited from the prototype’s properties.  The developer guide states, “Note: … controllers are not instantiated directly by Angular, but rather are applied to the scope object.”

Applying mixins with angular.extend

Luckily we have options, and a very good one is to use mixins.  I highly recommend reading these excellent posts on using JavaScript mixins:

In short, the mixin process is very simple and consists of copying the properties of one object to another. Here is AngularJS’s implementation of “mixing in” functionality from source object(s) to a destination object using the extend method:

The mixin pattern provides a great deal of flexibility by allowing us to not only “inherit” instance methods and properties, but $scope properties and methods as well.  Lets create a base AnimalController that applies these scenarios:

Now we can mixin AnimalController into DogController:

And then use DogController in our template:

What about Angular services?

You might be asking why not just use Angular services?  Services are great, I use them all the time, but primarily for the purpose of sharing information across controllers via dependency injection.  I don’t believe in passing a $scope object into a service to augment controller behavior.  That practice violates encapsulation, and completely exposes your controller logic to potentially dangerous conditions.  That being said, you could invoke a service method using call/apply with $scope as the context, for example:

4 thoughts on “Extending AngularJS Controllers Using the Mixin Pattern

  1. Taylor McIntyre

    Hey great post. Just curious, can this not be achieved with simply:

    AnimalController.call(this, $scope, ‘BARK BARK!’, ‘solid black’, ’35mph’)

    Instead of:

    angular.extend(this, new AnimalController($scope, ‘BARK BARK!’, ‘solid black’, ’35mph’));

    With your technique, you create a new instance of the parent controller, then attach all of the instance’s properties onto the child controller.

    Why not just invoke the parent controller with the context of the child-controller?

    Maybe I am missing something :/

    Reply
    1. bparvizi Post author

      Hi Taylor,

      Thanks for commenting. You could certainly do that as it’s basically doing the same thing. I think using the Angular API (angular.extend) is more semantic though. Another developer coming in would better grasp that a mixin pattern is being applied. One other consideration though, some mixin implementations check to see whether the destination object already has the property or method before the source is copied over. Having that layer of abstraction there in place of a simple call or apply would be better suited in that case. I haven’t had the time to update this post, but after using mixins for a while I would actually use them more sparingly. I’ll update the post and go into some of those issues. A good time to use mixins are in cases where you truly want to add in a particular piece of functionality rather than using them strictly for code organizational purposes. For example, I was writing a PhoneGap app that uses the bar code scanning plugin. It’s roughly about 50 lines of code to add the functionality. Mixing that into a controller is nice because I can give the controller instant bar code scanning capabilities.

      Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">