Jump to content



Mixins are a special type of controller that allow you to augment or change the functionality of an existing controller. This is particularly useful when you need to change something about how a built-in controller works.


Basic structure

This is the boilerplate for a mixin:

;( function($, _, undefined){
	"use strict";

	ips.controller.mixin('mixinName', 'core.global.core.table', true, function () {
		// Your code goes here

The method signature is:

ips.controller.mixin( string mixinName, string extendsController, boolean autoLoad, function mixinBody )
  • mixinName
    A name that will refer to this mixin
  • extendsController
    The full name of the controller that this mixin will extend (e.g. core.global.core.table)
  • autoLoad
    Boolean indicating whether this mixin should always extend the extendsController controller, or only when specified
  • mixinBody
    A function that returns the behaviors that the mixin defines


How a mixin works

A mixin works by allowing you to provide custom code that will execute at key points when the parent controller's method is called. To do that, there are three important methods available to a mixin:

  • before()
    Run the specified code before the parent controller's method
  • after()
    Run the specified code after the parent controller's method
  • around()
    The specified code is passed a reference to the parent controller's method, allowing it to be called when desired (and the return value modified

In addition to hooking into existing controller methods, your mixin can also provide new methods for its own use and, notably, simply redefine a method present in the parent controller in order to completely replace its functionality.


A note about this

Within the mixin body, you'll be adding methods to this. The mixin executes in the same context as the parent controller; that is, this in a mixin refers to both the mixin and the controller it extends, allowing you to call methods from the controller, and any create yourself in the mixin. During execution, they are one and the same.

The same is also true within methods in your mixin since, like in controllers, methods are automatically bound to the controller for you. You may be familiar with this.scope in controller methods (which refers to the DOM element onto which the controller is applied). Since mixin methods are bound in exactly the same way, using this.scope in a mixin method will still give you the element onto which the controller is applied.


before() and after()

The behavior of these two methods are very similar. They simply allow you to execute your custom code either immediately before, or immediately after the parent controller's code. Your custom code receives the parameters that are passed into the parent method, but not the return value (if any).

A common usage of either method is to add additional event handlers to a controller. A controller sets up its event handlers in the initialize method, and so a mixin can add more handlers like so:

this.before('initialize', function () {
	this.on('click', '#button', this._doSomething);
	this.on('click', '#button2', this._doSomethingElse);

In this case, our function will be executed, and then the parent's own initialize method will be executed.

In this example we don't deal with any parameters but, if the parent method is called with any, they will also be available to your mixin function as normal parameters, in the same order.



This behaves differently to the previous example, because rather than simply being executed before or after the parent, it actually provides the parent method as a reference to your own function. This allows you to call the parent method at a time of your choosing - perhaps determined based on some logic in your code. Since you have control over calling the parent method, you also have access to its return value, meaning that around can also be used as a way to modify the value that is returned from a controller method.

As an example, let's assume that the parent controller method returns a JSON object, but we want to augment this with some additional key/values. We can do this using the around call, like so:

this.around('parentMethod', function (origFn) {
	var returned = origFn();
	return _.extend( returned, {
		key1: true,
		key2: false

Notice that the parent method is passed in as a parameter (if the method has any other parameters, these will appear first, and the parent method will be the last parameter). We call this method in order to get its return value for our own use. When we look at the parent method we know that it returns a JSON object, so we extend it with our own values.

It's worth noting that since you receive both the original parameters, and a reference to the parent method, you have the ability to modify the parameter values before passing them into the parent method. This approach can offer a lot of flexibility.


Custom methods and replacing existing methods

Finally, you can create new methods in your mixin, or completely replace methods from the parent controller by redefining them. In both cases, this is done like so:

this.myMethod = function () {

Of course, if you replace an existing method, be sure it plays nicely with any calls to it!


Calling a mixin

Mixins can be applied to controllers manually when needed (you don't need to do this if you configured your mixing to automatically apply to the controller, though). To do so, specify the mixin name in parenthesis after the controller. For example:

<div data-controller='core.front.core.someController( mixinName )'>

Multiple mixins can be provided if they are comma-delimited.

Note that mixin files are not loaded on demand in the same way that controller files may be (but they will be compiled into bundles in the same way at build-time). In order for a mixin to be applied, it must be included in the page output. This means that if you're creating a plugin that (for example) has a mixin that applies to a core controller, you are responsible for ensuring the mixin file is included in the page as needed. This may mean creating a theme hook that modifies the output of the includeJS template.

  Report Guide