callLazy Function

If you are new to the site, check out the Lazy Function Pattern article and see its application with a timer in Deferred DOM Access. Todays article will show how the pattern can be abstracted into a general function, callLazy. This technique will allow developers to rewrite methods that are dependent on other methods and/or data to be immediately callable after defining, but before the dependent function is available, by waiting for the dependent to make itself available before executing.

Example 1: callLazy

var mes_callLazy = function(fx, isReady, m, n) {
	var max = (0 < m) ? m : 25,
		index = (0 < n) ? n : 0;

	if (index > max) {return;} // this prevents these calls from running forever

	if (fx) {
		if (isReady()) {
			fx();
		}
		else {
			setTimeout(function() {mes_callLazy.call(this, fx, isReady, max, index + 1);}, 100);
		}
	}
};

The method in Example 1 requires 2 parameters (fx, isReady) and accepts an additional 2 optional parameters (m, n). The fx parameter is the method to be executed after required method or data has loaded. The isReady parameter is a function that returns TRUE when the required method or data has loaded, and FALSE otherwise. Originally, isReady was a truthy object, but occasionally this caused issues with objects that were not inside a closure, so instead a closure is forced by requiring isReady to be a function. Lastly, m is the maximum number of times to attempt calling and n is the index of the current call; generally n should only be used by the call lazy function itself. The default numbers (25 for m and 100 for the timeout) will attempt to call the provided function (fx), 25 times over a period of about 2.5 seconds.

Most frequently I use this technique with objects that are loaded via AJAX. For example, on Mint.com, there are many in-page popups that the user can trigger. As developers, we do not want to slow down the initial page load, by preloading the HTML for all the possible popups. Instead, there is a fetch and cache system, which only grabs the popups as needed. However, since AJAX is asynchronous, the developer does not know when popup will be available.

Lets assume that before the DOM of each popup is fetched that a wrapper object is returned, an instance of Popup. The Popup object has lots of goodness available to it, but for the sake of this article, we will just consider open. The open method of Popup displays the popup on the page. Now consider that there is a link on the page, Show Accounts, which when clicked will trigger the AJAX request to get the popup, but use callLazy to immediately call the open method, so that as soon as the popup is rendered, it displays.

Example 2: Popup - Using callLazy

var showAccountCallback = function() {
    var popup = new Popup(account);
    
    if (popup.isRendered()) {
        popup.open();
    }
    else {
        popup.render(); // assume initializes AJAX request
        mes_callLazy(popup.open, popup.isRendered, 100);
    }
};

Example 2 will execute the "Popup.open" method as soon as the "popup.isRendered" method returns true. The maximum number of attempts has been increased to 100, because AJAX request performance can be degraded by many factors and a maximum timeout of 10 seconds is a more reasonable expectation.

The callLazy method can also be used to replace existing Lazy Function Patterns. For example suppose there is a method addClassToBody that adds a className to the BODY tag, but the developer is not sure that the BODY tag is available yet:

Example 3: Using callLazy for Lazy Function Pattern

var addClassToBody = function(className) {
    mes_callLazy(function() {
	var bd = document.getElementsByTagName(body)[0];

        addClassToBody = function(className) {
            YAHOO.util.Dom.addClass(bd, className);
        };

        addClassToBody(className);
    }, function() {
        return document.getElementsByTagName(body)[0];
    });
};

The developer calls addClassToBody from the HTML header, which then executes callLazy. The isReady method just checks for the existence of the BODY tag. Once the BODY tag is found, the execution method creates a pointer to the BODY tag, then overrides the addClassToBody function to instead apply a className to that pointer, before finally calling the overwritten function. A closure is used to remember the original className passed into the function before callLazy executed.

I find callLazy to be extremely useful, providing a consistent way to force method execution to wait. And although it works great as is, I do not like that there is no feedback if the callback execution times out. A future version of this tool will probably allow developers to pass in a failure function as well, so that you can attempt to recover from a function execution failure.

Validating Strings and Unsigned Numbers

One of the frequently overlooked JavaScript development practices is to validate the parameters passed into functions. Todays articles will look at two ways to validate string and an unsigned number parameters.

Example 1: Safe String Operation

var str_trim = function(s) { ( + s).remove(/^\s\s*/).remove(/\s\s*$/); };
Anytime a string is expected as a parameter, the developer has two approaches for validation: using a type detection function/comparison or simply ensuring that the parameter is a string ...

Extending Native String with SliceWord Function

The sliceWord function easily slice out a section of words from a string. This may be useful for form validation, DOM class manipulation, test replacement, and a whole lot more. The method is attached to "String.prototype", but could be easily modified to be standalone. Up to two optional parameters can be applied, where the first parameter is the word index to start (start index) slicing from, and the second parameter is the index of the ...

Get Common Ancestor Function

One way to improve the dispatch technique from last week is to only attach the single listener to the greatest common ancestor of all elements that we are dispatching. To achieve this, the following method to find the common ancestor of two elements was needed:

Example 1: Get Common Ancestor Function

YAHOO.util.Dom.getCommonAncestor = function(elem1, elem2) { var node1 = YAHOO.util.Dom.get(elem1), node2 = YAHOO.util.Dom.get(elem2); if (! (node1 && node2)) {return null;} // missing parameter, fail ...

Event Dispatcher

Modern web applications behave a lot like desktop applications, with nearly asynchronous updates, pre-caching of events and DOM, animations, drag and drop, etc. However, all these features come with a price, and a web application developer constantly considers add a new feature versus degrading site performance. Todays topic illustrates how you can reduce the cost of events leveraging an event dispatcher, EventDispatcher. From Widipedia:

Multiple dispatch or multimethods is the feature of some object-oriented programming ...

Simulating Events Using YUI

Sometimes when managing pages with unobtrusive JavaScript, especially ones leveraging events that need to bubble, two code paths are required: one for the event handler that properly bubbles, and another for the same action triggered by code. For example, a click event is attached to a div, containing many children, including several input elements. If the client clicks on one of the inputs, then both the input and the divclick events fire. However, if ...

Unique ID Generator

In preparation for an article on building and traversing node trees, I realized that I had not yet written an article covering a method to generate unique IDs, which is needed to provide a unique identifier for each node. We need a method that generates a unique string and does not repeat any ids. In addition, there should be an optional parameter to check that the ID does not yet exist in the DOM. Here ...

Scalable DOM Module With Rounded Corners

I am working on a homepage for this site and several other site improvements. For that work, I wanted a reusable DOM fragment with accompanying CSS that had rounded corners, a slight gradient background, and scaled well. Here is an example of what I designed. The HTML markup is fairly simple:

Example 1: Module HTML Markup

<div class="module"> <div class="moduleHeaderOuter"> <div class="moduleHeaderInner"><h3>Header Content Here</h3></div> </div> <div class="moduleContentOuter"> <div class="moduleContentInner">Content Here</div> </div> <div class="moduleFooterOuter"><div ...

Robust Get Element Dimension Function

As mentioned earlier this week, today we will be discussing a getDimension function that corrects for certain styles ("display:none" and "overflow:hidden") that cause an element to not have the proper height/width. This method contains generic logic that will determine if the element is "display:none" or "overflow:hidden", whether styled inline or via CSS (thanks to YUI), and temporarily correct those styles to determine the actual height/width of the element. It works with any element (not ...

Animated ScrollTo

This week I had the opportunity to write a method that wraps the native JavaScript window.scroll method with one that animates the scroll. The native window.scroll method is well supported by all Tier-A browsers and is a great way to ensure that dynamic content is visible on the screen. However, it is often jarring to the user when the page jumps to the desired position, so instead we will animate the scrolling.

Example 1: ScrollTo ...