AngularJS supports "mixins" with angular.extend, but this approach has some drawbacks. In this video Brett takes a look at a more robust approach to mixins inspired by the Ruby programming language.
Brett Shollenberger: Hey guys. Today we're going to talk about mixin pattern in AngularJS. The mixin pattern is really common in a lot of different languages. What it's going to allow us to do is to factor out reusable code that we want to include in a lot of different objects or classes or whatever into a single module so that we can reuse that module everywhere.
Kind of what we have defined here is just this mix into factory that we're not actually mixing into yet. We've just defined this cool true property. Over here, we're checking that cool does, in fact, equal true. We see here that it does.
But let's assume that we want to factor this out because we want to use this everywhere. We want everyone to know that cool is true. That makes sense, right guys?
What we can do here now that we've defined this mixin is to actually go ahead and inject it. Then Angular gives us this syntax called angular.extend. This takes something to mix into, which is this mix into object and something to mix in, which is this object down here. This is going to copy all the properties from this object to this object, so even if we get rid of this, this still works.
But what's not actually going to be expected for us is if we try to override this by saying cool is false. In a lot of other languages, we would expect that to be true. But that's not so in this case.
What we actually want to do here is have the mixin be kind of like a pseudo parent class. It's not actually going to be a parent of this object, but it's going to kind of inject itself into the hierarchy there like it would in other languages.
The way that we do that is by actually using a bower component that I've made for us here called Pocketknife. This provides us with this PK mixin functionality. The difference is that if the receiving object doesn't have a property already by the given name, then it'll override it. Again, this isn't really injecting itself into the hierarchy, but it's just kind of simulating what that would do.
What this actually lets us do is save things like whether or not we can enumerate over that property in the object and what the value of the property is, or we can define a getter function and the setter function. All kinds of stuff that we may want to do.
Just to show you really what that's capable of, what I'm going to do is copy this enumerable functionality out of Pocketknife that I've already defined for us. This is very similar to Ruby's implementation of the enumerable module that gives many different objects like arrays and hash tables the ability to be enumerated over. We're going to inject in enumerable.
What that's going to do is allow us to, on our array prototype actually mixin this enumerable functionality. We can see that if we comment that out first and we were to test things like 123.collect and we pass it a function of the number. We want to return that number plus 1. We would expect, if 123 had 1 added to each of those, it would be 234. We're going to get this object, array has no method collect error.
What we're going to actually do is uncomment this. We're going to mixin these enumerable functions from enumerable into the array prototype. Now we get this spec passing.
Just to kind of show you what we had access to, let's just kind of get rid of some of the rest of these. We need to have the each method still, and we need to have collect, because collect uses the each method.
But if we set enumerable to true here, all of a sudden, not only do we have 2, 3 and 4, but we also have the collect function as a property in our array, or an item in our array. The reason is because enumerable gives us control over whether or not that object can be iterated over. Again, if we set it to false, now things work the way that we expect them to.
That's how I'd recommend creating your mixins, guys. Happy mixing in.