Sencha Ext JS 7.7 is Here – Discover What’s New and Exciting – LEARN MORE

Using Plugins and Mixins in Your Sencha Apps

October 23, 2014 107 Views
Show

Introduction

Using Plugins and Mixins in Your Sencha AppsWhen extending the functionality of a framework class, you generally write the new functionality directly into the derived class. However, if you need that same functionality to exist in multiple components, the most efficient option may be to define it in a plugin or mixin. Plugins and mixins are classes that add extra functionality to another class. In this article, we’ll talk about what these classes are, how they differ, and how they work. I’ve also included Sencha Fiddle examples to illustrate these concepts.

What is a Plugin and How Do I Use it?

A plugin is a class that adds to or modifies the function of an Ext.Component (or class derived from Ext.Component). Like any class, plugins are defined using Ext.define() and extend Ext.plugin.Abstract.

// Simple example showing how to define a plugin
// extending form Ext.plugin.Abstract

Ext.define(‘Fiddle.plugin.SamplePlugin’, {
extend: ‘Ext.plugin.Abstract’,
alias: ‘plugin.sampleplugin’,

init: function (cmp) {
this.setCmp(cmp);
}
});

However, it could really be any class you define that has an init(cmp) method because that’s what will be called by the component’s constructor prior to the component being rendered. The plugin is included and configured via the component’s “plugins” config which can be set on the class body when a custom component is originally defined [Fiddle] or in a config object during instantiation. [Fiddle]

When creating a plugin from an extension of Ext.plugin.Abstract, you receive init(), destroy(), enable(), and disable() methods by default. Let’s talk about how you can use each one effectively.

init()

The init() method is the entry point for the plugin. It allows the plugin to interact with the component it’s being plugged into prior to it rendering. The plugin needs to store a reference to the client component at this stage, so the methods defined on the plugin can then easily reference it. Ext.plugin.Abstract provides two accessor methods to reference the component using the plugin:

  • setCmp() – use setCmp(cmp) in init(cmp) to initially set a reference to the component on the plugin for use by getCmp()
  • getCmp() – this accessor method is used by other methods defined on the plugin

The getCmp() method is particularly important because the plugin and its methods operate within the scope of the plugin itself. In other words, the this reference is the plugin, not the client component using the plugin. A getter method to access the client component is handy when plugin methods need to interact with the owning component.

The init() method may set up the plugin logic at the time init() is processed; other times the plugin logic may need to be set up once its owning component is rendered. For example, a drag and drop region needs to be created once the component’s HTML is rendered to the DOM. In this case, you need to set a listener on the client component’s afterrender event and set up the functionality of the plugin at that time. [Fiddle]

destroy()

The plugin’s destroy() method is called when the client component is destroyed. Any class instances that were created by the plugin (e.g. drag and drop, key navigation, etc.) need to be destroyed programmatically at this time. Any convenience properties set on the client component’s instance should also be nulled or deleted. [Fiddle]

enable() / disable()

The enable() method simply sets the plugin’s disabled property to false and the disable() method will set disabled to true. You can extend this functionality when creating your own plugin. You can also leverage any plugin logic by first checking the disabled state before proceeding. This has the potential to go as deep as you like, depending on how involved enabling or disabling the plugin needs to be. [Fiddle]

Fetching a Reference to the Plugin

Since the methods defined on the plugin belong to the plugin and not the component using it, you need to get a reference from the component back to the plugin to call its methods. Or, you can bind the plugin method to the component for added convenience. [Fiddle]

When defining your plugin class, it’s helpful to give it an alias prefixed with plugin like:
alias: plugin.myplugin. When a client component uses that plugin, it now has an easy way to configure the plugin by type:

plugins: [{
ptype: ‘myplugin’
}]

The alias also allows you to use the component’s findPlugin() method to search for a reference to the plugin. For instance:

var thePlugin = owningClass.findPlugin(‘myplugin’);

Finally, you can get a reference to a plugin using the component’s getPlugin() method and pluginId:

plugins: [{
ptype: ‘myplugin’,
pluginId: ‘myPluginId’;
}]

var thePlugin = owningClass.getPlugin(‘myPluginId’);

What is a Mixin and How Do I Use it?

A mixin is a class that also adds functionality to a class. However, it operates a bit differently than a plugin in the following ways.

  1. Mixins can be used to add functionality to any class, while plugins are used with an Ext.Component class.
  2. Mixins are declared only within a class definition using the “mixins” config, whereas a plugin may be declared on a class definition or on a class instance.
  3. Mixins may be designed to operate very generically on any class they’re mixed into (see Ext.mixin.Observable which adds event fire/listen functionality to any class it’s mixed into). That said, it can also be more expressly scoped to a particular category of classes (see Ext.panel.Pinnable which is designed to be mixed into panel classes only).
  4. Methods defined on the mixin are applied to the prototype of the target class.

When you create an instance of a class using a mixin, you call any mixin-defined method directly from the class. The scope of this within the method will be the owning class itself. [Fiddle] It’s possible to define a method on your mixin that has the same name as a method on the owning class. In this case, the mixin method is not set on the target class prototype. Calling the method on the class will still call the original class-defined method.

To call a mixin’s method of the same name, you fetch a reference to the mixin from the owning class (more below) then call the mixin method directly. When calling the mixin’s method directly, the scope is the mixin. So, “this” will be the mixin itself. [Fiddle] As an example, if the mixin had a mixin id of ‘util’, calling the mixin-defined destroy method would look like this:

this.mixins.util.destroy.call(this);

Defining Your Mixin

A mixin may be any class defined by Ext.define(), though we recommend extending Ext.Mixin. The primary benefit of extending Ext.Mixin when defining your mixin class is that it allows you to define “hooks”. Hooks are methods defined on the mixin that are called automatically before or after a corresponding method on the receiving class. For example, you can ensure that your mixin’s afterDestroy() method is called after the class has been destroyed by using an ‘after’ hook:

mixinConfig: {
after: {
destroy: ‘afterDestroy’
}
}

For more details on how to use the “before’, “after”, “on”, and “extended” hooks, see the description at the top of the Ext.Mixin API doc.

Using Your Mixin

The preferred way to use your mixins is to use the full class name in an array. The mixins will be processed in the order they are listed in the array.

mixins: [
‘My.utility.MixinClass’ // “util” is used to reference the mixin
]

The object syntax (see option 2 below) offers backwards compatibility, but it’s not recommended because the key name used will not respect the id defined on the mixin class.

Fetching a Reference to the Mixin

You may want to fetch a reference to a class’s mixin from the class instance. This is done using a reference to the owning class instance’s “mixins” property followed by the id of the mixin (e.g. “this.mixins.util”). We recommend always setting a unique mixin id when defining your mixin class. There are three ways that mixin ids may be set/determined:

    • You can set a mixinId config on the mixin class body if it does not extend Ext.Mixin. For instance:mixinId: ‘util’
    • or if the mixin does extend Ext.Mixin, you can set an id config in the mixinConfig like
      this:mixinConfig: {
      id: ‘util’
      }
  1. Mixins can also be defined as an object and each mixin is keyed with a name/id. For instance:mixins: {
    util: “My.utility.MixinClass”
    }
  2. When an id is not set using the above methods, the mixin’s full class name can be used:Ext.define(‘My.utility.MixinClass’);
    var utilMixin = owningClass.mixins[‘My.utility.MixinClass’];

When to Use a Plugin Versus a Mixin

Now that we’ve covered what a plugin and a mixin are, you may wonder when you should define your class as a one versus the other. Because the same functionality could potentially be written into either class type, you want to think about how the functionality will be used within your application. A plugin offers a bit more flexibility because it can be used on instances and therefore only adds overhead to that instance. However, if the functionality is needed on all classes, then defining the logic in a mixin can be more efficient because a plugin instance will not be spun up as each class instance is created.

coming soon

Something Awesome Is

COMING SOON!