Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Extending jQuery: Defining Your Plugin

DZone's Guide to

Extending jQuery: Defining Your Plugin

· Web Dev Zone
Free Resource

Learn how to build modern digital experience apps with Crafter CMS. Download this eBook now. Brought to you in partnership with Crafter Software

This post is an excerpt chapter from Manning Publications' "Extending jQuery" by Keith B. Wood.

Although you could develop each plugin on its own, as they each provide specific functionality, it makes sense to reuse code as much as possible, since they all interact with jQuery in much the same way. To this end, I have developed a plugin framework that has served me well in my own plugins. It provides the common capabilities on all collection plugins and makes it easy to add extra commands and options.

The MaxLength plugin

The example plugin we want to develop provides a maximum length restriction for textarea fields, similar to the built-in maxlength attribute for input fields. It is called as follows with default settings:

$('#text1').maxlength();

To customize the plugin you provide options to the initialization call.

$('#text1').maxlength({max: 400});

Figure 1 The MaxLength plugin in operation

The plugin also allows you to just warn the user when they reach the maximum number of characters without preventing them from entering more. In this way, the user knows that they have to reduce the text, but are not cut off in the middle of a train of thought. Instead, they can go back and edit the text themselves to bring it back into line. Different text appears in the feedback when the length is more than the imposed maximum.

Feedback may be suppressed altogether, although it is a better user experience when it is provided or may be set to show only when the textarea is active, in other words, when hovering over it or when it has focus. And the user may be informed of a textarea reaching or exceeding its maximum via a callback event.

The MaxLength plugin follows the principle of providing progressive enhancements. It enriches the user experience with regards to entering limited text into a textarea field. Without JavaScript, you can still enter text and the length restriction will be imposed on the server when the value is submitted (as it should be anyway).

There are a few basic steps required before you can start developing the specific functionality of your plugin. These are:

  • Claiming a name for the plugin.
  • Protecting your code from the wider JavaScript environment, and vice versa.
  • Defining a singleton-like object to provide access to common settings and behavior.


Claiming a namespace

Every plugin needs a name to identify it and to separate it from other plugins. You should pick a name that reflects the purpose of the plugin and that you can use throughout, in keeping with the principle of only claiming a single name and using that for everything within jQuery. You might use a slightly different name within your documentation for the plugin, but the two should be closely related.

Note that this name is the access point to your plugin. If you choose the same name as another plugin then the two will not be able to operate together on the same page. Presumably though, if they have the same name they are providing very similar, if not the same, functionality, so there is less likelihood that they would both be required together.

For this plugin, you’ll use the name “maxlength,” since this is exactly what the plugin provides. It is not too long and not so short such that it loses its meaning. In the documentation, you could refer to the plugin as “MaxLength.”

In keeping with general jQuery guidelines, the name should be used as all lowercase characters. Also, your plugin code should appear within a file named jquery.<pluginname>.js, with related files being named in the same pattern. So, for this plugin, the code appears in jquery.maxlength.js, while the associated CSS appears in jquery.maxlength.css.

Encapsulation

Two of the guiding principles—hide the implementation details and don’t rely on $ being the same as jQuery—can be solved by using some boilerplate code that serves to protect your plugin’s implementation from the rest of the JavaScript environment—known as encapsulation in object-oriented programming.

Firstly, in #1 you declare an anonymous function that serves as a closure, i.e. variables and functions defined within this function are not visible externally. Thus you can apply whatever naming convention you wish to your own plugin’s internal code without worrying that it will conflict with external code or another plugin. Anything that you want to be accessible from outside your plugin is made available via the jQuery object itself.

Having declared this wrapper function, you surround it with parentheses to ensure that it is available for use, and then immediately call it (#2). The parameter to the function call is the jQuery object. Referring back to the function declaration, you see that it takes one parameter, which it calls $. The jQuery object is thus mapped directly onto the $ parameter and the latter may be used within the body of the function knowing that it will always refer to jQuery and not be usurped by some other JavaScript library.

NOTE: You have probably seen that most jQuery code is wrapped in a $(document).ready(function() {...}) callback, or its shorthand form $(function() {...}). This is to ensure that the code is not executed until the DOM is available for use. You do not wrap your plugin code in the same structure since you want it to execute as soon as it is loaded and to be subsequently available when the normal jQuery initialisation is run. If you do need to set up something within the DOM as part of your plugin, it should be deferred until it is actually needed, usually when your plugin is applied to a set of elements or can be wrapped in its own document.ready callback from within the plugin.

Using a singleton

To simplify interactions with the plugin, and to act as a central repository of information and behaviour, I use aspects of the singleton pattern, whereby there is a single instance of an object with a global access point. In addition to defining the abilities of the object, via its internal functions, it contains constants and values that apply across all applications of the plugin to elements on the page.

A class-like definition is declared in JavaScript as a function (#1). The name of this function is not visible externally due to your use of the closure, so it does not have to be the single name you picked for the plugin. In fact, it may be a little clearer for your code if the name is different.

That function may have its own set of internal fields and subfunctions declared to define its state and behavior. The this variable refers to the current instance of that “class.” Most importantly, the plugin defines a set of default options that control its behavior (#3). Ideally, these options provide the entire configuration necessary to allow the plugin to be applied to an element and have it work in a default manner. Any of these options may be overridden by the user when they initialize the plugin on their own elements.

To allow the options to be easily localized for other languages and cultures, an array of localizations is defined (#2) and is initialized with the default (English) settings. These are added to the other default settings once the latter have been defined (#4). As other localizations are provided they can be applied as follows:

$('#text1').maxlength($.maxlength.regional['fr']);

Additional constants and internal functions are defined by extending the function prototype (#5). These functions implement the abilities of the plugin. Several are common across all plugins and the rest are specific to the current functionality.

Finally, to make the singleton available to external code, you create the one instance of it and assign it to an attribute of the jQuery object (as aliased by $ [#6])—following the place everything under the jQuery object principle. Note that you use the single name selected for your plugin for this purpose. You also create a local variable—plugin—to reference the plugin for use within this module, making it easier to reuse the framework code in other plugins.

Using this technique makes it easy to reference plugin constants, variables, and functions even in callback functions that may have a different context.

Summary

The plugin you’ve defined complements the existing functionality provided by the browser. Normal text input fields have a maxlength attribute that allows you to limit how much text may be entered into them. Such a restriction helps enforce limits that may be imposed by databases and other storage mechanisms. However, the multiline textarea field has no such attribute and allows unlimited text entry. To address this situation, you can create a collection plugin to control the amount of text that is accepted, and to provide valuable feedback on the way.

Extending jQuery by Keith B. Wood

jQuery usually operates under a select and action pattern. You find the elements of interest, either directly by selectors and filters, or by traversing the DOM from an existing selection, and then apply some functionality to them. These actions are what I call collection plugins; in other words, they operate on a collection of DOM elements that are wrapped in a jQuery object. The majority of third-party jQuery plugins are of this type. In this article based on Extending jQuery, you’ll define a relatively simple plugin that provides a useful service, while still being complex enough to show most of the principles involved in any plugin.

Here are some other Manning titles you may be interested in:

Rails 3 in Action, Second Edition
Ryan Bigg   

Sass and Compass in Action
Wynn Netherland, Nathan Weizenbaum, and Chris Eppstein

Secrets of the JavaScript Ninja

John Resig and Bear Bibeault

Crafter is a modern CMS platform for building modern websites and content-rich digital experiences. Download this eBook now. Brought to you in partnership with Crafter Software.

Topics:

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}