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

Entries Tagged as 'Widget'

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.

Event handling in jQuery widgets

Posted by Dave Mahon

This is simple – provided you understand that the reference the keyword this refers to changes depending on when it is called.

When called during initialization, this refers to the widget you’re initializing. When the event itself is triggered, this refers to the DOM node node and not the widget.

As such, we need to introduce a new variable during initialization which the jQuery.UI library calls self which is, of course, equal to the initialization this, not triggered this. (Those of you familiar with Object Oriented Programming and by-reference calls should have no issue with this concept).

<$.widget("ui.clicker", {
   _init: function() {
      self = this;
      this.element.click(function() {
         self.increment(self);
         self.render();
      });
      this.render();
   },
   increment: function(target) {
      target.value(target.value()-1);
      //The exact handling of target.value will be shown another day
   },
   render: function() {
      this.element.text(this.value());
   },
   value: function(val) {}
});

You’ll note that we have to pass self to the increment method or the widget won’t actually be able to find itself, but the render method, which was called during initialization, is henceforth always able to correctly reference this (the widget)!

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').

YUI Calendar Popup from Text Input

Posted by Don Albrecht

I needed a way to provide my users with a date picker that was automatically provided when a text area received focus.  I was eager to use the excellent YUI calendar as a starting point, but the provided documentation didn’t provide a solid example for this type of implementation.

Dav Glass has provided a solid example of the Calendar tied to a text input. But, his example is highly dependent on the text input having specific ids.  This doesn’t take advantage of YUI’s excellent Selector library really didn’t meet my need for a simple universal solution.

Key Requirements:

  1. Progressive Enhancement (No inline javascript)
  2. Yui based
  3. Universal implementation across all pages in a site.
  4. Support for multiple date inputs on a page.

Getting Started:

The bulk of the code used is pretty solidly Dav’s I’ve simply replaced all of the hard coded references to dynamically generated targets and moved from hard coded ID’s for the target fields to a css class.  Lastly, I’ve added a “activeCal” class to the currently active target input so that one calendar can be recycled across multiple text areas on the page.

Source:

var cal1;
var over_cal = false;
function transmogCals() {
    cal1 = new YAHOO.widget.Calendar("cal1","cal1Container");
    cal1.selectEvent.subscribe(getDate, cal1, true);
    cal1.renderEvent.subscribe(setupListeners, cal1, true);
    var pickers =  YAHOO.util.Selector.query('.date-picker'); 
for( i in pickers){
    YAHOO.util.Event.addListener(pickers[i], 'focus', showCal);
    YAHOO.util.Event.addListener(pickers[i], 'blur', hideCal);
    }
cal1.render();
}
function setupListeners() {
    YAHOO.util.Event.addListener('cal1Container', 'mouseover', overCal);
    YAHOO.util.Event.addListener('cal1Container', 'mouseout', outCal);
}
function getDate() {
        var calDate = this.getSelectedDates()[0];
        calDate = (calDate.getMonth() + 1) + '/' + calDate.getDate() + '/' + calDate.getFullYear();
        YAHOO.util.Selector.query('.activeCal')[0].value = calDate;
        over_cal = false;
        hideCal();
}
function showCal(e, targ) {
    var xy = YAHOO.util.Dom.getXY(this);
    var el = new YAHOO.util.Element(this); 
    el.addClass('activeCal');
    var date = this.value;
    if (date) {
        cal1.cfg.setProperty('selected', date);
        cal1.cfg.setProperty('pagedate', new Date(date), true);
        cal1.render();
    }
    YAHOO.util.Dom.setStyle('cal1Container', 'display', 'block');
    xy[1] = xy[1] + 20;
    YAHOO.util.Dom.setXY('cal1Container', xy);
}
function hideCal() {
    if (!over_cal) {
         var el = new YAHOO.util.Element(this); 
        el.removeClass('activeCal');
        YAHOO.util.Dom.setStyle('cal1Container', 'display', 'none');
    }
}
function overCal() {
    over_cal = true;
}
function outCal() {
    over_cal = false;
}
YAHOO.util.Event.addListener(window, 'load', transmogCals);

 

Adding it to your page

Integrating the code into the page is VERY easy.

In the header of the page add the following css includes.

<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/combo?2.6.0/build/calendar/assets/skins/sam/calendar.css">
In the footer add the following script include and include the date-picker.js file
<script type=“text/javascript” src=“http://yui.yahooapis.com/combo?2.6.0/build/yahoo-dom-event/yahoo-dom-event.js&2.6.0/build/calendar/calendar-min.js&2.6.0/build/selector/selector-beta-min.js”></script> 
Lastly, place a class of date-picker to any text fields you want to tie to the input and add the following to your pages markup:

 

<div class='yui-skin-sam' style="position:absolute; left:-1000px;">
     <div id="cal1Container"></div>
   </div>

Expand your debugging aresnal with pi.debugger

Posted by Don Albrecht

pi.debugger is a new debug console that acts as a graceful counterpart to firebug.  I’ve  and Firebug is an awesome tool for debugging, hands down.  Unfortunately, it is Firefox specific and has to be installed on the clients machine.

Firebug lite is great, but it is extremely limited and provides little more than a logging console.  pi.debugger sits somewhere in between.  It’s not as full featured as firebug, but it does provide the ever useful evaluation console as well as a DOM browser.

Check it out here:

http://code.google.com/p/pi-js/

And test drive it here:

http://kodfabrik.com/app/pi.debugger/

Ajax24’s Drop Tabs. A Creative Take on The Tab Box for Scriptaculous

Posted by Don Albrecht

Tab Boxes are one of the most ubiquitous and popular of widgets. They pop up in everything from news sites to accounting software and for good reason. After all, tabs are one of the simplest and most efficient ways to cram more into a given block of screen real-estate than would fit otherwise.

Ajax24’s drop tabs replace the normal tab-box behavior concept with a twist. THese tabs pull blocks of content down from a tab bar to make them available and float them above the background content. (think window blinds or drawers as opposed to tabbed sheets of paper). I have a few reservations about the use of a widget with such slightly unconventional behavior. But all in all, the smooth motions of the widget and it’s novelty surely warrant exploration in more playful interfaces.

You can find the widget at

http://www.flash-free.org/en/2008/04/05/e24tabmenu-–-menu-desplegable-ajax/

Widget.Blender Smooth Image Morphs For Prototype

Posted by Don Albrecht

Widget.Blender is a handy prototype class to smoothly animate a fade/morph transition between images

Features

  • Start & Stop can be triggered by events
  • Autosizing & Wrapping can be controlled
  • Ability to set a standard base url / dir for all images
  • Ability to start at any arbitrary image
  • Ability to run arbitrary function before blend (Useful for setting caption to display along with image)
  • Supported Browsers:
    • Firefox 2
    • Opera 9
    • IE 6
    • IE 7
    • Safari

Check out Widget.Blender at:

http://www.eternal.co.za/scripts/blender/index.html 

Making The Browser "Aware" of AJAX Requests

Posted by Don Albrecht

I recently discovered a fascinating prototype extension called LOAJAX. While the effect of the extension is a bit hard to describe, it’s immediately obvious when you try the demo’s with and without it. Basically, LOAJAX uses an iFrame crutch to make the browser display all of the interface elements associated with a page load.

How it works:

  1. A normal AJAX XMLHttpRequest is triggered by the AJAX application.
  2. LOAJAX creates a hidden iframe that points to a server script.
  3. The browser displays loading behavior while the iframe loads its source.
  4. The Server Script consists of a massive wait so the load never completes.
  5. When the XMLHttpRequest is completed, LOAJAX stops the iframe load and removes it from the DOM.
  6. The browser stops displaying page load indicators.

You can find more about LOAJAX and check out the demo here:

http://blog.loajax.com/

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