Design Patterns: Mixin

Brett Cassette
InstructorBrett Cassette
Share this video with your friends

Social Share Links

Send Tweet
Published 11 years ago
Updated 6 years ago

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.

Now, if instead of angular.extend, we said, pk.mixin, this will work the way that we expect it to. What's even more is PK mixin gives us a lot of fine grain control over the way that we define how our properties get mixed in. It does that through this object.define property syntax that's given to us by JavaScript.

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.

Really, what Pocketknife is giving you access to is this kind of fine grained control where you can say exactly how you're defining the properties on your mixin object. If I were to give one piece of advice to look into after the screencast, it would be all the options that you have here on this object.define property method in JavaScript.

That's how I'd recommend creating your mixins, guys. Happy mixing in.

eric
eric
~ 11 years ago

I felt like this lesson moved far to quickly, and didn't have the kind of immediately practical takeaways as a lot of the other lessons. I'm trying to dig into this kind of pattern right now and was hoping for the same kind of insights other lessons have provided. Using this pattern without a practical example, immediately jumping into a 3rd party library, and only showing how it applied to testing didn't really help me understand Angular.extend or a lot of the core principals that make this pattern so good. I'd love to see a deeper dive into the mixin pattern, and maybe with a little more background into when something like this is useful.

Joel Hooks
Joel Hooks
~ 11 years ago

I'd love to see a deeper dive into the mixin pattern, and maybe with a little more background into when something like this is useful.

Since watching this lesson I've started using this pattern quite a bit. I love it, in fact. I've got some practical uses for it and it is on my backlog!

Mark
Mark
~ 11 years ago

in app.spec.js do you need a var superArray ; with a small s after var SuperArray; ?

Joel Hooks
Joel Hooks
~ 11 years ago

as it is now it is implicit assignment of the variable, which is definitely not the best way to go (though it should work). You should always be explicit with variable declaration in JS!

Mark
Mark
~ 11 years ago

Thanks, I realize now that I had added 'use strict' to the top of the file that was not in the original source.

Attend Product
Attend Product
~ 10 years ago

This was brilliant, thanks!

Markdown supported.
Become a member to join the discussionEnroll Today