Having fun with Mixins in Angular

Mixins in Angular — The Good, the Bad and the Ugly

Photo by freestocks.org on Unsplash

In my last post I wrote about Statemanagement in Angular. At the end I wrote about a Connect Mixin I had in my mind at that time. Okay to be honest I had a Higher Order Component in mind, but that’s not so easy to achieve in Angular. So let’s take one step after the other. The purpose of the Connect Mixin would be to connect to a NGRX Store and provide us with data from it. Finally it made it into this writeup. If you don’t read the whole post I would encourage you to skip to the Connect-Mixin part. Or at least read the last part: Are Mixins bad?

1️⃣ What are Mixins?

MixIn programming is a style of software development where units of functionality are created in a class and then mixed in with other classes. A mixin class is a parent class that is inherited from — but not as a means of specialization. Typically, the mixin will export services to a child class, but no semantics will be implied about the child “being a kind of” the parent — [1]

In my own words: Mixins are a special kind of class inheritance. They give you the power of multiple inheritance and allow you to use code from many different classes. But why?

2️⃣Why Mixins? 🤷🤷‍

They enable us to share cross functional behaviour. Say we have some generic functionality to connect to our redux store and some shared functionality that we want to share with many views. A naive approach could look like the following snippet:

Multiple Inheritance via extend is not allowed

But the compiler is not quite happy with this. An error is thrown at us:

Classes can only extend a single class!

How can we solve this problem? Mixins to the rescue 🚑. Let’s directly dive into some code. To achieve the desired behaviour from above we have to create some functions that mix in (MixIn^^) the behaviour. Such a Mixin Function expects at least one argument, namely the class we wanna extend. And thats exactly what is happening inside the function. It’s returning a Class Expression that extends from the given class and adds additional behaviour on top of it:

Sample of MixIns

Now we can enhance our base class CommitView with the Connect-Mixin behaviour and the View-Mixin behaviour. I don’t wanna go into great detail about Mixins itself, because there is already a great introduction by Marius Schulz.

Basically a Mixin function takes a class definition and enhances it by extending from it. In my example above the View-Mixin adds the viewMode field and the Connect-Mixin connects to a specific store implementation. For the complete implementation of the Connect-Mixin please scroll down to 4⃣.

3️⃣Mixins in Angular Material

While looking through some Angular Material source I noticed that there are Mixins used too. This was kind of a surprise, but it makes perfectly sense. They have many shared functionality across the different directives like a Color Mixin, Disabled Mixin, Tabindex Mixin, Error Sate Mixin or Initialized Mixin. Building multiple base classes with all different variants of behaviour would be simply not beneficial and maintainable. I think this is a perfect example of a valid usage of Mixins.

Have a look at the Color Mixin:

Before the introduction of Mixins in Angular Material, the same code was copied and pasted again and again over multiple components.

4️⃣The Connect Mixin

As promised above, here comes the Connect Mixin. Its task is to work similar to the Connect Higher Order Component from React Redux. It allows you to specify selectors and actions that are then mixin’d to the given Component.

In this mini sample I’v created and connected a Counter Component to an NGRX store.

Boring counter — I know

Let’s take a look at of the usage of the Connect Mixin ⬇. Notice that it shows a very thin implementation of a container component. The container serves exactly one purpose: Connecting the counter component. That’s a different yet clean approach to container components. Why different? In Angular Applications I often see very big container components that connect all kind of data from the store and do additional business logic on them. They fail the Single Responsibility Principle in some way.

In order to be able to use the dependency injection of Angular we have to add the class CounterViewBase in between and extend the container from the created Mixins class. This is because a Mixin classes must have a constructor with a single rest parameter of the type any[] and so we can’t inject the Injector directly into the Mixin.

In the template below we directly call the methods that got bound on the container through the Connect-Mixin. These methods are accessible through the vm object. This is a limitation we have to take in order to stay AOT compatible. You could name it whatever you like though. Important is only that the variable is known by the template in advance.

The counter container template

The Connect-Mixin itself expects a component that has an injector, therefore we’v created the HasInjector interface. We need the injector to get the NGRX Store Service at runtime. We could have injected the NGRX Store directly in the container but I wanted to decouple the container from the store implementation we are using.

Although I’m not using the vm object in the container component in this example, the types Inputs<I> and Outputs<O> would give us a type-safe handling of it.

5️⃣Are Mixins bad?

I have to admit that I was a favor composition over inheritance evangelist until I made this writeup. I tried to avoid inheritance, especially multiple inheritance, at all cost. But the world is not just black or white, and for component libraries like Angular Material using multiple inheritance via Mixins does make sense.

I would not overuse Mixins though.

If you need much more dynamic behaviour in your components I would strive for “Composition over Inheritance”. Composition allows for interchangeable behaviour at runtime and adheres to the Open closed principle.

Still in line

Next post will be on the topic of Mixins vs Higher Order Components.

If I’ll keep up my pace it will be finished in June 2019. Just kidding 🐢

Checkout out the full source of the example on Github

🍀 💚 All the best for 2019 💚 🍀

Follow me on Twitter :)