Ajax Bestiary: A Javascript Field Guide
 
Ajax Bestiary: A Javascript Field Guide
 
 

How to Write a jQuery Plugin

Posted by Don Albrecht

I know there’s a slew and a half of tutorials on this out there, but I’m adding my own to the mix.  I’ve been working on a generic template for plugin development and have cobbled together what I feel is a solid one.

First thing first, however, building a plugin is about being a good citizen

  1. You’ve got a naming convention to deal with.  jquery[your plugin name].js
  2. Be considerate of the $.XXX namespace.  Only claim 1, and try to make it both developer friendly and unique.  In our case it will be $.plugin
  3. Always return this.
  4. Always end with a “;”
  5. Wrap the entire thing in an anonymous function call, this will protect the plugin from instances where jquery has been renamed. 

So, with all that said and done, the skeleton of a plugin looks like this:

   1: (function($) {

   2:  

   3:   $.fn.myPlugin = function(settings) {

   4:     var config = {'foo': 'bar'};

   5:     if (settings) $.extend(config, settings);

   6:     this.each(function() {

   7:       // element-specific code here

   8:     });

   9:     return this;

  10:   };

  11:   

  12:    var newMethods = {

  13:        a   : function() {

  14:                 var config = {'foo': 'bar'};

  15:                 if (settings) $.extend(config, settings);

  16:  

  17:                this.each(function() {

  18:                   // element-specific code here

  19:                 });

  20:  

  21:                 return this;

  22:                   },

  23:        b   : function() { return this },

  24:        c     : function() { return this }

  25:       };

  26:       

  27:  jQuery.each(newMethods, function(i) {

  28:    jQuery.fn.myPlugin[i] = this;

  29:  });

  30:  

  31:  

  32: })(jQuery);

 

Note, what this code is doing.

First, we define the core behavior of the plugin, then extend the plugin once.  This way we keep our declarations concise, clear and well encapsulated.

We have an established closure structure for shared private functions.

We keep everything encapsulated to protect the jquery namespace as much as possible, and iterate over the child functions to extend the plugin.

PS– most of this is adapted from the jquery extension guide here: http://docs.jquery.com/Plugins/Authoring

Getting and setting values for jQuery widgets

Posted by Dave Mahon

If you come from an OOP background you’re likely used to defining class variables like this:

class MyClass {
   var internalValue1;
   var internalValue2;
   function constructor() {}
}

The values which are to be stored in your object are simple, straightforward, likely to be typed, and the compiler will detect typos in the variable names. JavaScript, as a loosely types language which treats its objects more like collections than discrete objects, can’t really offer us those protections. Conversely, that also means that we have a great deal of flexibility.

In essence, we can dynamically subclass our objects, which you have to admit is a neat trick.

So, for jQuery.UI widgets, the variables stored within our widget are not defined until we assign them. The act of assignment defines the variable name, which can then be called upon at will.

Assignment is simply:

this._setData(‘variablename’, variablevalue);

Retrieval of this value is similarly straightforward:

this._getData(‘variablename’);

This does mean that the old problem of misnamed variables is alive and well. It also means that you need to be prepared to handle an undefined response to the _getData call.

Customized context menu handling with jQuery

Posted by Dave Mahon

Can you think of some times you might want to disable the right click context menu? Or better still, insert your own behavior or application specific context menu?

This is a simple and useful trick:

element.bind('contextmenu',function(e){
    //Optional customized handling here
    return false;
});

If you don’t return false, the normal context menu will appear, which could actually be desirable, depending on what exactly you want it to do (say, exiting a field and recording it as dirty).

Helpful error handling in jQuery

Posted by Dave Mahon

If you’re going to build a reusable tool, you’re going to want to be able to detect, handle and report error messages in a nice, clean way. It will make you and any other dev happy.

The cleanest way of handling genuine errors for developers using your tool – namely, invalid input sent to a function in the library – is to log it to the console. Doing so is refreshingly straightforward:

var err = new Error();
err.name = "jQuery.widget.UI.clicker.range()";
err.message = "Both values must be numeric to assign range";
throw(err);

This snippet comes straight from the widget I threw together. I encourage you to make the name as detailed as possible. It will make debugging so much easier. You can even pinpoint the exact point of error if the problem was say, an invalid query syntax. (Handy during the development phase; not so much in a production environment!)

Custom stateful jQuery widgets

Posted by Dave Mahon

The widget library included in jQuery UI is pretty cool, but sometimes you need to roll your own custom object. If it didn’t have to be reusable, you could always just use a whole slew of bind methods on a specific page. Likewise, if network bandwidth and latency weren’t an issue, you could just store everything server-side and make heavy use of XmlHttpRequest.

Of course we don’t live in that ideal world and so we need to store data locally and our objects inevitably need to be reused. Enter the jQuery Widget Factory. This nifty feature set included in jQuery UI satisfies all of these needs.

Further, implementing custom widgets is pretty easy. First, we’ll initialize the widget:

$.widget('ui.widgetname', { _init: function() {} );

Then we’ll set any defaults:

$.ui.widgetname.defaults = {};

Obviously, this can and should be in its own file. Then on the specific web page, we can instantiate the widget:

$(target).widgetname();

This affords us the flexibility to reuse the widget multiple times on the same page and across pages and sites. Tomorrow we’ll start working up a rather basic example of this.

Before then, note that we use the widgetname consistently in its definition and instantiation, so choose the name wisely. Collisions in the $.ui namespace seem unlikely, but in very complex applications, that is always a possibility.

You’ll also note that in the widget’s definition we included only an _init function. This is the generic constructor for the widget and the only required method; feel free to add more as needed. The underscore prefix declares the method “private” and can be used to prefix any function in the widget declaration. This being JavaScript, we know that hidden named functions are quite impossible, but it does conceal the method from the now deprecated $(element).plugin('function').

Cross Site Scripting – the new old way

Posted by Dave Mahon

Cross Site Scripting (XSS) is a big security no-no. It’s never supposed to happen, because as we all know, any script operating within your page has full access to the entire DOM of the page.

Then again, there is so much functionality that we want to implement without reinventing the wheel. Marketing departments want to use third-party tracking tools. The IT folks want to distribute the load for our network heavy site across the third-level domains www.domain.com, static.domain.com and data.domain.com. And users want more functionality than we can hope to provide on our own.

So resigned to the reality that XSS is a legitimate necessity, we need a way to do it. The old way (as far back as the mid-90’s, in fact) was straightforward:

document.write(<script language=”JavaScript” type=”text/javascript” src=”http://data.domain.com/myscript.js”></script>’);

This is of course problematic as it treats DOM nodes improperly and may not even get processed by modern browsers. Instead, jQuery provides access to JSONP which will do the same thing – insert a new script node in the DOM – but do it in an XHTML compliant way.

Accessing JSONP is pretty straightforward:

$.getJSON("http://data.domain.com/myscript&callback=?”, inPageFunction);

The key bit is &callback=? – this causes jQuery to insert a script node into the DOM, which is then immediately executed and returned to the callback function, inPageFunction, like so:

inPageFunction({data:"foo";})

If you forget &callback=? you’ll get the error Access to restricted URI denied. And yes, since we’re inserting a script node, we’re limited to GET requests. And if the call fails, you’ll simply get nothing back – no useful error messages.

Further, the next generation of browsers is coming out with integrated support for cross site XMLHttpRequest, but since when have we not had to code to support multiple versions of browsers?

There are loads of good guides to expand your knowledge:

Using the jQuery data method as a local datastore

Posted by Dave Mahon

At some point, we all have to store datasets on the client. We can clutter the namespace with ever more variables and try really hard to avoid collisions. We can cram variables into some local object that we’re using in the normal execution of our script anyway. We can attach custom attributes to HTML nodes, violating the sacrosanct purity of XHTML.

Or we can attach the document-specific variables, in script (thus keeping those automated validators happy), to the document itself. This fairly intuitive approach has not been given the notice it deserves.

Some advantages:

  1. Arbitrary value names can be assigned and we can basically assign as many of these variables as we want.
  2. They can be applied to anything jQuery can access, meaning that we can rapidly assign values to entire sets of DOM nodes without having to add CSS classes or clutter the markup.
  3. They can be dynamically added, accessed, changed and removed at will, without network transfers.

There is the disadvantage that they are not persistent across page loads, but we’ve lived with that problem for a long, long time, haven’t we?

So how do we use this handy method? The documentation is pretty clear cut, but I’ll give a slightly more grounded example:

My HTML is very simplistic in this example:

1
2
3
4
5
6
7
8
<body>
 <div>
  <span id="stats"></span>
  <button id="add">Add Data Point</button>
  <button id="reset">Reset Set</button>
 </div>
 <div id="data"></div>
</body>

The JavaScript is similarly intuitive:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
appExample = {
 addDataPoint: function() {
  var dat = this.getDataSet();
  dat[dat.length] = Math.floor(Math.random()*101);
  $('#data').data('points', dat);
 },
 resetDataSet: function() {
  $('#data').removeData('points');
 },
 dataSize: function() {
  var dat = this.getDataSet();
  return dat.length;
 },
 getDataSet: function() {
  var dat = $('#data').data('points');
  if (undefined == dat) return [];
  if (Array != dat.constructor) return [dat];
  return dat;
 },
 updateDisplay: function() {
  $('#stats').text('Data Points: ' + (lim = this.dataSize()));
  var tmp = '';
  var dat = this.getDataSet();
  for (var i = 0; i < lim; i++) {
   tmp += dat[i];
   if (i < lim - 1) tmp += ',';
  }
  $('#data').text('[' + tmp + ']');
 }
}
 
$(document).ready( function() {
 appExample.updateDisplay();
 $('#add').bind('click', function(e) {
  appExample.addDataPoint();
  appExample.updateDisplay();
 });
 $('#reset').bind('click', function(e) {
  appExample.resetDataSet();
  appExample.updateDisplay();
 });
});

In this case, I’m storing everything as an array in points. While I’m storing randomly generated integers, you can just as easily store entire objects, opening the possibility of a JSON solution.

Note that we can identify those objects lacking the chosen dynamic attribute by calling it and testing for undefined.

jQuery Corners

Posted by Don Albrecht

Proto Corner

I covered the Prototype port of this plugin a while ago, but recently realized that I had neglected to cover the original version. jQuery corners is an excellent library for adding quick corner effects to your pages in a graceful and unobtrusive way.

Here are some highlights of the plugin’s capabilities:

  • A whole slew of effects is available.
  • The width and height of the adornment area can be changed to vary the effect.
  • You can apply different effects to top and bottom corners, or apply an effect to specific corners.
  • Boxes to be adorned are selected using the standard JQuery $() element selector function.
  • No special markup is required; display falls back to unadorned corners when Javascript is off.
  • You can define your own custom corner effects that the plugin will use.

Learn more about the plugin at
http://www.methvin.com/jquery/jq-corner.html

Flot 0.2 Released

Posted by Don Albrecht

Ole Larson has released a new version of Flot:
Key Changes

  • Added support for putting a background behind the default legend.
    The default is the partly transparent background color. Added
    backgroundColor and backgroundOpacity to the legend options to control
    this.
  • The ticks options can now be a callback function that takes one
    parameter, an object with the attributes min and max. The function
    should return a ticks array.
  • Added labelFormatter option in legend, useful for turning the legend
    labels into links.
  • Fixed a couple of bugs.
  • The API should now be fully documented.
  • Patch from Guy Fraser to make parts of the code smaller.
  • API changes: Moved labelMargin option to grid from x/yaxis.

Most notably, the new packaging includes the modified excanvas script in the zip download to greatly simplify deploying with IE support.

Read about it here:

http://ole-laursen.blogspot.com/2007/12/flot-02-released.html 

24 Hours with Flot

Posted by Don Albrecht

flot2.pngAlright, So Flot 0.1 has been out in the wild for just under 2 days now and it’s gotten some pretty decent traction with the Ajax blogs.  I’ve taken some time over the past 24 hours to work with the library and I have to say, It’s pretty awesome. Highlights:  

  • The presets really are excellent , simple charts are very little work.
  • The charts look great, the integrated support for shadows & alpha channels really makes them shine
  • The underlying architecture is excellent.  I’ve been able to get under the hood and add needed features without any major headaches. 
  • jQuery based

Shown: A chart created with a modified version of Flot with normal range highlighted. You can get flot at: http://code.google.com/p/flot/