Archive

Author Archive

Using multiple versions of jQuery

October 3rd, 2009

Whenever a new version of jQuery comes out, there are several reasons to upgrade; new features, bug fixes and performance are generally the most common. However, it’s not always possible to upgrade as soon as a new version comes out. The new version may contain an API change that would break some of your functionality or you may be using a plugin that isn’t compatible with the new version. This is where jQuery.noConflict() comes in.

History of jQuery.noConflict()

jQuery.noConflict() was added in v1.1 to support loading jQuery on a page with other code that uses the global $ variable. In this version, the only thing that jQuery.noConflict() did was revert the $ variable to what it was before jQuery was loaded. In v1.1.1, this function was modified to also return the jQuery object so that you could assign jQuery to another variable (though it was still also assigned to the global jQuery variable). v1.1.4 introduced a boolean parameter for jQuery.noConflict() to indicate whether the global jQuery variable should be reverted; this option was added to make it easy to load multiple versions of jQuery on the same page.

Using jQuery.noConflict()

Using jQuery.noConflict() to load multiple versions of jQuery is actually pretty simple. There’s essentially just one rule: load your plugins in the correct order. In order for this to work, you have to include one version of jQuery and all of the plugins for that version before including the next version and all of its plugins. You can call jQuery.noConflict() immediately before including the second version or after you have included all the plugins for the second version. Both methods will have the same final outcome, but it may be easier to keep track of what’s going on if you call jQuery.noConflict() immediately before loading the next version in the unlikely event that you need to include more than two versions of jQuery on the same page. Because this method is slightly easier to follow, we’ll use it in our example.

First we need to load both versions of jQuery:

<!-- load jQuery 1.1.3 -->
<script type="text/javascript" src="http://code.jquery.com/jquery-1.1.3.js"></script>
<script type="text/javascript" src="jquery.dimensions.min.js"></script>

<!-- revert global jQuery and $ variables and store jQuery in a new variable -->
<script type="text/javascript">
var jQuery_1_1_3 = $.noConflict(true);
</script>

<!-- load jQuery 1.3.2 -->
<script type="text/javascript" src="http://code.jquery.com/jquery-1.3.2.js"></script>

<!-- revert global jQuery and $ variables and store jQuery in a new variable -->
<script type="text/javascript">
var jQuery_1_3_2 = $.noConflict(true);
</script>

Now we can use either version of jQuery by using the two new variables we’ve created:

jQuery_1_1_3('<button>Use jQuery 1.1.3</button>')
	.click(function() {
		alert('Top: ' + jQuery_1_1_3(this).offset().top + '\n' +
			'jQuery: ' + jQuery_1_1_3.fn.jquery);
	})
	.appendTo('body');

This is great, but you’re probably looking at that code and thinking “I wish I could still use the $ variable.” Well, with a little help from a self-executing anonymous function, you can!

(function($) {
	$('<button>Use jQuery 1.1.3</button>')
		.click(function() {
			alert('Top: ' + $(this).offset().top + '\n' +
				'jQuery: ' + $.fn.jquery);
		})
		.appendTo('body');
})(jQuery_1_1_3);

This is a pattern you’ll see in a lot of plugins (in fact it’s part of what makes this whole thing work). We’ve created a function that accepts a single parameter, $, and we call that function as soon as we define it, passing our jQuery object to it. Now we can reference our jQuery object as $ inside this function. This makes it very easy to rename your global jQuery object while keeping your existing code working with minimal modifications.

View this example in a new window

jQuery , , ,

Creating dialogs on demand

August 7th, 2009

In a previous article, I explained how to load a page into a dialog. The article focused on a simple solution to keep it easy to understand. However, that simplicity does come with a drawback; the page contents are loaded immediately after the document is ready, even if the user never opens the dialog. In this article, I’ll show how to load the page on demand while still only making a single request regardless of how many times the user opens the dialog.

On-demand page loading

In order to create the dialog on the first click, we’ll take advantage of jQuery’s .one() event binding method.one() binds a handler to an event, but the handler is only ever run once. Immediately after the handler runs it unbinds itself, preventing further execution. We’ll adapt the example from the previous article to take advantage of .one():

$(document).ready(function() {
	$('#page-help').each(function() {
		var $dialog = $('<div></div>');
		var $link = $(this).one('click', function() {
			$dialog
				.load($link.attr('href'))
				.dialog({
					title: $link.attr('title'),
					width: 500,
					height: 300
				});

			$link.click(function() {
				$dialog.dialog('open');

				return false;
			});

			return false;
		});
	});
});

Adding the final touch

Now that we’ve got our dialogs loading on demand, we need to account for network latency, slow connections, etc. Previously we were loading the page contents before the user ever saw the dialog, so any delay was hidden. A simple solution for this is to just show a loading image inside the dialog until the page contents are loaded. We’ll load this image immediately on document ready to make sure that it’s ready for use when the user clicks the link to open the dialog. Loading images are generally very small in terms of file size and they can be cached by the user, so the overhead of loading the image up-front is negligible.

$(document).ready(function() {
	var $loading = $('<img src="loading.gif" alt="loading">');

	$('#page-help').each(function() {
		var $dialog = $('<div></div>')
			.append($loading.clone());
		var $link = $(this).one('click', function() {
			$dialog
				.load($link.attr('href'))
				.dialog({
					title: $link.attr('title'),
					width: 500,
					height: 300
				});

			$link.click(function() {
				$dialog.dialog('open');

				return false;
			});

			return false;
		});
	});
});

View this example in a new window

jQuery UI - Dialog , , , , ,

Loading a page into a dialog

April 18th, 2009

I previously showed the basic usage of the jQuery UI dialog.  In this article, I’ll show how to open a page in a dialog.  We’ve all been to sites where there’s a help link that opens a popup with some short help text.  This is usually done with a simple window.open call attached to the click event of the link.

<a id="page-help" href="page.html" onclick="window.open(this.href, 'popupwindow', 'width=500,height=300'); return false;">what is this?</a>

Making it better

The one thing that this code has going for it is that users without JavaScript will still be able to get to the page with the help content. Of course, a better implementation would move the JavaScript out of the HTML, properly separating content from behavior.  We can spruce this up by loading the content into a dialog instead of a new window:

$(document).ready(function() {
	$('#page-help').each(function() {
		var $link = $(this);
		var $dialog = $('<div></div>')
			.load($link.attr('href'))
			.dialog({
				autoOpen: false,
				title: $link.attr('title'),
				width: 500,
				height: 300
			});

		$link.click(function() {
			$dialog.dialog('open');

			return false;
		});
	});
});

How it works

We’re finding the link, loading the contents of the linked page into a div and creating a dialog from that div.  We then bind a click event to the link to show the dialog.  This code by itself will work in many situations.  However, the page you’re linking to may have a heading that you’re already reproducing with the dialog title.  There may also be other elements on the page that won’t make sense in a popup, such as navigational elements or a page footer.  Luckily the .load() function allows us to pass in a selector to find the contents that we care about.  In this example we’ll assume the main content of the page is in a div with an id of content.

$(document).ready(function() {
	$('#page-help').each(function() {
		var $link = $(this);
		var $dialog = $('<div></div>')
			.load($link.attr('href') + ' #content')
			.dialog({
				autoOpen: false,
				title: $link.attr('title'),
				width: 500,
				height: 300
			});

		$link.click(function() {
			$dialog.dialog('open');

			return false;
		});
	});
});

View this example in a new window

jQuery UI - Dialog , , ,

Basic usage of the jQuery UI dialog

April 8th, 2009

The jQuery UI dialog, like many jQuery UI plugins, is extremely easy to get started with but has a few areas that causes new users some trouble.  One of the most commonly asked questions on the jquery-ui list is “Why does my dialog only open once?”  In this article I’ll explain the problem these users are running into and how to get your dialogs to show each and every time.

Problem:

All jQuery UI plugins maintain state, such as the current option values, whether the plugin is enabled or disabled, which plugins have been initialized on the element, etc.  This state persists from the time the plugin is instantiated on the element until it is destroyed, either explicitly by the user calling .pluginName('destroy') or by removing the element (or one of its ancestors) via .remove().  Because of this state management, you cannot instantiate the same plugin on an element multiple times, unless you destroy the plugin instance first.

The problem that users often encounter with dialogs is that they try to instantiate a new dialog every time the user performs some action (generally clicking a link or a button).  This is an understandable mistake because at first glance it seems like calling .dialog() on an element is what causes the dialog to open.  In reality what is happening is that a new dialog instance is being created and then that instance is being opened immediately after instantiation.  The reason that the dialog opens is because dialogs have an autoOpen option, which defaults to true.  So when a user calls .dialog() on an element twice, the second call is ignored because the dialog has already been instantiated on that element.

Solution:

The simple solution to this problem is to instantiate the dialog with autoOpen set to false and then call .dialog('open') in the event handler.

$(document).ready(function() {
	var $dialog = $('<div></div>')
		.html('This dialog will show every time!')
		.dialog({
			autoOpen: false,
			title: 'Basic Dialog'
		});

	$('#opener').click(function() {
		$dialog.dialog('open');
	});
});

View this example in a new window

jQuery UI - Dialog , , , , , ,