Advanced Plugin Development with Ext JS

来源:百度文库 编辑:神马文学网 时间:2024/04/28 02:21:23

Advanced Plugin Development with Ext JS

November 11, 2009 by Nigel White

When creating a cross browser RIA, choosing a framework with a plethora of components is where most of us look first. There comes a time, however, when the framework might not have the specific component or functionality we need. Here, selecting a framework that enables you the flexibility to enhance and expand its offering becomes very important. Fortunately, Ext JS has all the rich UI functionality that most applications require coupled with a vibrant community creating impressive extensions. However, sometimes, you will want to add extra capabilities to a component for which an extension is not available. Ext’s elegant design allows us to explore our creativity by adding new features to existing widgets. We will explore several ways to approach this advanced task.

What is an Ext Plugin?

An Ext Plugin is a class (It could also be a singleton object) which is configured into a Component in the plugins config option. All plugins must implement a method named init which is called by the Component, passing itself as the sole parameter at initialization time right at the beginning of the Component’s lifecycle, before it has been rendered.

Upon gaining control, a plugin must initialize itself to add capabilities and processing to its client Component.

This is usually done by augmenting certain methods of the client Component by specifying new functions to run either before or after the base Component’s method. This is done using Ext’s additions to all JavaScript functions, createInterceptor or createSequence. Each of these functions will be explained individually as they become relevant.

Approaches to Adding Functionality

When an application developer needs to enhance, or change the functioning of an existing Ext Component there are several options open each of which has advantages and disadvantages.

For example, Ext’s form Fields receive the fieldLabel configuration when used in a Container with a layout of form. Imagine that we want to eliminate this requirement and allow Fields to manually render their own labels. Ext is flexible enough that we can add this functionality in many different ways.

There are three possible options:

Component configuration (Option 1)

The developer may choose to configure the input Fields with listeners on published events which use the published interface of the TextField class to achieve the requirement. This may be done by using the listeners configuration or setting up event handlers after the component is instantiated with the on method.

In a one-off situation, this might be the easiest option, but as soon as the requirement needs to be repeated in different situations, code duplication can arise. In this case, it’s immediately obvious that we cannot add such complex new processing into each configuration of every Field.

Another disadvantage is that events may be programmatically suspended, or may be cancelled by existing event handlers rendering the added listeners inoperative.

Create a subclass (Option 2)

In a subclass, the developer overrides the template methods (more of which later) which provide the structure and lifecycle flow of the Component. The equivalent template method in the superclass is called either before or after the additional functionality is performed.

A possible implementation of a self labeling TextField class.

The disadvantage here is that forking off a subclass at any level in the hierarchy to add capabilities to a class, “strands” any existing subclasses of the augmented class. They are left without access to the extra functionality.

In this case, we’ve created an enhanced TextField which renders its own label, but this leaves subclasses like TriggerField, TextArea and NumberField unable to take advantage of the added functionality.

Another disadvantage is that if there are two subclasses of a base class which both implement some new capabilities, and a developer wants to use both sets of new capabilities, this is not possible.

Create a plugin (Option 3)

This option offers the most flexibility in terms of code reuse because if carefully written, a plugin for one class is usable by subclasses of that class. Also, multiple plugins may be used in a Component. This obviously requires that the plugins do not conflict with each other.

Implementing a Plugin

Before we dive into an implementation, let’s examine how a plugin can entwine its required functionality around the existing functionality in an Ext Component without using events.

We avoid using events because there is no guarantee that our plugin’s listener would be called before or after other event handlers. Other listeners might stop the event by returning false, or events may be programatically suspended.

Instead, we augment methods within the host Component which allows our plugin to gain control at important points in the component lifecycle.

The Template Method Pattern

Ext JS’s Component class hierarchy uses the Template Method pattern to delegate to subclasses, behaviour which is specific only to that subclass.

The meaning of this is that each class in the inheritance chain may ‘contribute’ an extra piece of logic to certain phases in the Component’s lifecycle. At each phase, a class implements its own special behaviour while allowing the other classes in the inheritance chain to continue to contribute their own logic. The template methods are analogous to events, they perform internal processing at defined points in Component lifecycles which loosely correspond to events.

An example is the render function. Instead of having to override it and duplicating its complex code, it provides you with hooks or Template Methods which each subclass can implement. The two hooks that are executed during the render process are onRender and afterRender. Every subclass implementor can add class-specific processing to any template method. By calling the hook on the superclass and up the entire inheritance hierarchy, we allow each class to contribute its own behavior while keeping the inheritance chain in tact.

The diagram above illustrates the execution of the onRender template method up the entire inheritance chain within a Component. When the render method is executed it will call this.onRender which is the implementation within the current subclass (if implemented). For example, if a subclass of Panel called MyPanel is being rendered, MyPanel.onRender is called. This method performs the special processing that makes the class different from the Panel class and calls the superclass version which calls its superclass version etc. Each class contributes its specific functionality, and control eventually returns to the render function.

There are several Template Methods in the Ext JS Component lifecycle which provide useful points to implement class-specific logic.

The Template Methods available to all Component subclasses are:

  • onRender

    Allows addition of behaviour to the rendering phase. After calling the superclass’s onRender, the Component’s Element will exist. Extra DOM processing may be performed at this stage to complete the desired structure of the control.

  • afterRender

    Allows addition of behaviour after rendering is complete. At this stage the Component’s Element will have been styled according to the configuration, will have had any configured CSS class names added, and will be in the configured visibility and the configured enable state.

  • onAdded

    Allows addition of behaviour when a Component is added to a Container. After calling the superclass’s onAdded, the Component will hold a reference to its parent Container in its ownerCt property.

  • onRemoved

    Allows addition of behaviour when a Component is removed from a Container. After calling the superclass’s onRemoved, the Component will have no ownerCt reference.

  • onShow

    Allows addition of behaviour to the show operation. After calling the superclass’s onShow, the Component will be visible.

  • onHide

    Allows addition of behaviour to the hide operation. After calling the superclass’s onHide, the Component will be hidden.

  • onDisable

    Allows addition of behaviour to the disable operation. After calling the superclass’s onDisable, the Component will be disabled.

  • onEnable

    Allows addition of behaviour to the enable operation. After calling the superclass’s onEnable, the Component will be enabled.

  • onDestroy

    Allows addition of behaviour to the destroy operation. After calling the superclass’s onDestroy, the Component will be destroyed.

Further Ext classes down the hierarchy add their own Template methods which are appropriate to their own capabilities. To learn more about adding functionality within template methods read the Creating New UI Controls article in the Learn section of our website.

Hooking into Template Methods

A plugin needs to insert some extra processing either before or after its client Component’s template method executes. To do this, we need to understand how to create function interceptors and function sequences.

Interceptors

An interceptor function is a function which a developer uses to perform some functionality before an existing function performs its own functionality. As an example, let’s insert some functionality before Observable’s fireEvent method so that we can log all Ext events to the Firebug console. (Warning: there will be lots!)

// A class's methods are stored in its prototype, so grab that.var o = Ext.util.Observable.prototype; // This is the function we will be executing before the real fireEventMethod.// It will be passed all the same argments, and has the same scope (this reference).// Log the firer, the event name, and the arguments to the console. function fireEventInterceptor(evt) {var a = arguments;var msg = "fired the following event {0} with args"; console.log(this);console.log(String.format(msg, evt));console.log(Array.prototype.slice.call(a, 1, a.length));} // Set the class's fireEvent to be our interceptor.o.fireEvent = o.fireEvent.createInterceptor(fireEventInterceptor);

It’s that simple. Our function always gets called before Ext’s original fireEvent method.

Sequences

A sequence is a function which gets executed after an existing function.

Our plugin implementation uses sequences to add its own processing after the processing of the Field has taken place.

A FieldLabeler Plugin

In this case, the plugin is a singleton. It cannot be instantiated. It is specified simply using:

plugins: [ Ext.ux.FieldLabeler ]

It augments several of its client Field’s template methods with its own methods. These execute as if they were member methods of the Field. Their this reference is the Field itself, so they can perform any processing which may be necessary at that particular lifecycle phase. This is why a singleton may be used – all contextual information is in the client Component.

The three methods we augment within our plugin are:

  • onRender
    Our added code renders extra DOM elements.
  • onResize
    Our added code ensures the extra DOM elements are sized properly
  • onDestroy
    Our added code ensures the extra DOM elements are cleaned up.

By implementing this functionality as a plugin rather than a subclass we have eliminated the problem of our downstream plugins not receiving the added functionality. This plugin is capable of being integrating with TriggerField, TextArea and NumberField without a problem.

Take a look at the example of this plugin in action here. The source has been comprehensively documented and is available here.

Summary

We explored different ways to implement custom functionality and specifically how to create reusable plugins without creating a fragile class hierarchy. Using plugins to augment Ext’s baseline functionality is one of the best approaches when you want to be able to mix and match functionality. The most important concept to grasp is that we can provide additional functionality by augmenting existing methods within a component that are guaranteed to be executed during a components lifecycle. We encourage you to take a look at the thousands of plugins available on the Ext Forums. We hope that our post and community inspire you to take the plunge into Ext plugin development.