Introducing React ReExt – Sencha Ext JS Components in React! LEARN MORE

Use Of Plugins and Mixins in Sencha Apps

October 23, 2014 172 Views
Show

When extending the functionality of a js frameworks‘ class, the new functionality is usually written straight into the derived class. If you need the same functionality in several components, the most effective solution may be to specify it as a plugin or mixin. Plugins and mixins are classes that extend the functionality of another. This article will explain what these classes are, how they vary, and function. Plus, we added Sencha Fiddle examples to help you understand these ideas.

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 a 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 be any class you design that has an init(CMP) method because that’s what the component’s constructor will call before the component is shown. The plugin is included and configured using the component’s  “plugins” config. This could be placed on the class body when defining a custom component  or in a config object during registration 

When generating a plugin from an Ext.plugin extension, you will receive the methods init(), destruct(), enable(), and disable() by default. Let’s go over how to use each one efficiently below.

What is the init() method?

The init() method is the plugin’s entry point. It enables the plugin to communicate with the component into which it is connected before processing. At this point, the plugin must store a reference to the client component so that the methods defined on the plugin can readily reference it. The Ext.plugin. abstract includes two accesso methods for referencing the component via the plugin. For example;

  • 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 plugin’s scope. In other words, 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 when 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 components after render event and set up the plugin’s functionality at that time.

What is the destroy() method?

The plugins destroy() method is called when the client component is destroyed. Any class instances 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.

How is the enable() and disable() method used?

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 Itugin. 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.

How to Fetch 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.

When defining your plugin class, it’s helpful to give it an alias prefixed with plugins 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 id:

 

plugins: [{
ptype: 'myplugin',
id: '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 differently from a plugin in the following ways.

  1. Mixins can 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. 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. For 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);  

How To Define 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 is 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.

What Is The Best Way To Use 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 backward compatibility, but it’s not recommended because the key name used will not respect the id defined on the mixin class.

How To Fetch a Reference to the Mixin?

The safe way 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. They are;

  1. 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'
    }

    2. Mixins can also be defined as an object and each mixin is keyed with a name/id. For instance:

    mixins: {
    util: “My.utility.MixinClass”
    }

    3. 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 Should You Use a Plugin vs. a Mixin?

Now that we’ve covered what a plugin and a mixin are, you may wonder when you should define your class as 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. Here are two major factors you should consider;

  • 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.