jQuery Minute™

…a jQuery Minute™ later and you're done!

SwitchView Plugin Released

without comments

Greetings all!

I’m pleased to release a new plugin called switchView. The SwitchView jQuery plugin provides the ability to easily define groups of elements to show and hide in one fell swoop. Let’s take a look at how the plugin works!

Given the following HTML:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<p>
    <label>Username</label>
    <input type="text" name="username" />
</p>
 
<p>
    <label>Password</label>
    <input type="text" name="password" />
</p>
 
<p>
    <label>Confirm Password</label>
    <input type="password" name="confirmPassword" />
</p>
 
<a href="#">Change Password</a>
 
<input type="submit" value="Login" />
<input type="cancel" value="Cancel" />
<input type="submit" value="Change Password" />

The requirement is to toggle between a set of elements for the “login” view and the “change password” view. When using the switchView plugin, you define a “view” simply by placing a CSS class prefixed with view-on- on an element (the prefix can be configured). So let’s define two views: view-on-login and view-on-change-pw. Then to switch to the change-pw view, do:

1
$('body').switchView('changePw');

Now let’s look at how we would add the CSS classes to our elements:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<p>
    <label>Username</label>
    <input type="text" name="username" />
</p>
 
<p>
    <label>Password</label>
    <input type="text" name="password" />
</p>
 
<p class="view-on-change-pw view-hidden">
    <label>Confirm Password</label>
    <input type="password" name="confirmPassword" />
</p>
 
<a href="#" class="view-on-login">Change Password</a>
 
<input type="submit" value="Login" class="view-on-login" />
<input type="cancel" value="Cancel" class="view-on-change-pw view-hidden" />
<input type="submit" value="Change Password" class="view-on-change-pw view-hidden" />

You’ll notice that I didn’t add any classes to the Username or Password fields as these are used in both views. Another option would be to place two view classes on those such as:

1
2
3
4
<p class="view-on-login view-on-change-pw">
    <label>Username</label>
    <input type="text" name="username" />
</p>

Additionally the view-hidden class has a single rule of .view-hidden { display: none; } which is used to hide elements by default.

Two final points to wrap up here, the context and groups. In the code below:

1
$('body').switchView('changePw');

The switchView plugin is looking for any elements that contain a view-on-* class within the BODY. It’s possible to scope switchView to only work on say a div with ID #navigation.

1
$('#navigation').switchView('changePw');

The one thing to watch out for, is if you change the view based on the BODY element, it will then potentially hide the elements inside of #navigation which is most likely not what you want. So to address this, the switchView jQuery Plugin provides for the concept of a “group”.

1
2
3
4
5
6
7
<div class="view-group-login">
<p>
    <label>Username</label>
    <input type="text" name="username" />
</p>
...
</div>

Now that we have grouped our login form, we would do the following:

1
$('body').switchView('login.changePw');

You can still use ungrouped elements, but doing so will not affect the elements within the view-group-login. It’s also worth noting that you can have grouped elements located anywhere on the page. So for example, if you have two parts to your form that are in physically different locations in your document, you can just add a view-group-login to each section.

jQuery switchView Plugin by jdsharp

Enjoy!

Cheers,
- Jonathan

Written by jdsharp

November 24th, 2009 at 12:56 pm

Posted in Plugin-Extension

Duplicate and Clone Elements Multiple Times

without comments

Greeting again from the heartland. Here is a quick plugin that duplicates one or more elements n times. This function is similar to the clone() method but will clone the elements multiple times placing them in the same collection. If you were to call clone 5 times such as:

1
$('<div></div>').clone().clone().clone().clone().clone();

it would give you 5 separate collections of a div. The duplicate plugin below, puts a new collection of all elements duplicated on the jQuery stack.

1
2
3
<ul id="myList">
    <li><a href="http://www.flickr.com/photos/jdsharp-com/4088227698/">Percheron's are cool</a></li> 
</ul>

So here’s an example use case given the HTML above:

1
$('li').duplicate(5).appendTo('#myList');

The above code starts by selecting all LI on the page (in this case only 1 of them) then duplicate’s it 5 times and appends the duplicated element to the UL with an ID of myList.

Now for the plugin:

1
2
3
4
5
6
7
$.fn.duplicate = function(count, cloneEvents) {
	var tmp = [];
	for ( var i = 0; i < count; i++ ) {
		$.merge( tmp, this.clone( cloneEvents ).get() );
	}
	return this.pushStack( tmp );
};

Having this plugin return this.pushStack( tmp ) is what gives us a new collection. To pop this collection off the stack and return to our original elements call .end(). One final note, cloneEvents can be set to true to have jQuery’s clone method also clone any attached events. By default it clones just the element and not attached events.

That’s all for now!
- Jonathan

Written by jdsharp

November 9th, 2009 at 8:15 am

Calculating The Sum of Inputs

without comments

Greetings all, here’s a quick plugin to sum up the values of inputs or even html elements. I wrote this plugin recently for a fellow developer who had a series of input boxes that needed to be totaled. Let’s first take a look at the html:

1
2
3
4
5
6
Price 1: <input type="text" name="price01" class="price" /><br/>
Price 2: <input type="text" name="price02" class="price" /><br/>
Price 3: <input type="text" name="price03" class="price" /><br/>
Price 4: <input type="text" name="price04" class="price" /><br/>
Price 5: <input type="text" name="price05" class="price" /><br/>
Total: <span class="total"></span>

The HTML above allows for entering a price for each of five items. (price01 through price05). While it is possible to manually select each element and sum their totals, in the actual use case there are a number of additional inputs.

1
2
3
4
5
6
7
8
9
10
11
12
$.fn.sumValues = function() {
	var sum = 0; 
	this.each(function() {
		if ( $(this).is(':input') ) {
			var val = $(this).val();
		} else {
			var val = $(this).text();
		}
		sum += parseFloat( ('0' + val).replace(/[^0-9-\.]/g, ''), 10 );
	});
	return sum;
};

Now the actual plugin starts by iterating over each of the inputs that the user selected (in our case the selector is input.price) and keeps a running tally. Line 4 determines of the current element selected is an input element, otherwise it uses the .text() jQuery method to return the contents of the element minus any HTML tags. Line 9 strips out any non-digit characters, – and . and parses the string into a float. ('0' + val) portion ensures that we have at least a value in the field. Finally the second argument to parseFloat() ensures that the float is parsed in base 10 for the conditions where the user entered a leading zero.

Finally, let’s make use of our plugin and wire it up:

1
2
3
4
5
$(document).ready(function() {
	$('input.price').bind('keyup', function() {
		$('span.total').html( $('input.price').sumValues() );
	});
});

On line 2 we bind the keyup event to all inputs with a class of price, sum up the values of those inputs and assign the result to span.total. There you go!

Until next time,
- Jonathan

Written by jdsharp

November 6th, 2009 at 8:00 am

jQuery add or remove class with toggleClass

without comments

Back in May of 2008 I posted about how to dynamically call a jQuery function and the practical use in adding or removing a class in one fell swoop. Since that post the toggleClass method has been updated to accept a second argument, a boolean value to signify adding or removing a class.

First the classic toggle class example:

1
$('body').toggleClass('blue');

Which just as the method describes will add the class “blue” if it doesn’t exit or remove it if it does.

In the next example we make use of addClass or removeClass

1
2
3
4
5
if ( $('body').hasClass('makeBlue') ) {
    $('body').removeClass('blue');
} else {
    $('body').addClass('blue');
}

Which has the same result and function as our first example with the difference that we’re adding or removing a class based upon the condition of body having the class “makeBlue”.

So here is an updated example making use of toggleClass along with the second argument that when true adds the class and conversely if false removes the class.

1
2
var addBlue = $('body').hasClass('makeBlue');
$('body').toggleClass('blue', addBlue );

And the final reduced version:

1
$('body').toggleClass('blue', $('body').hasClass('makeBlue') );

Cheers,
- Jonathan

Written by jdsharp

October 3rd, 2009 at 12:13 am

Finding Immediately Adjacent Siblings

without comments

Greetings! Here’s a quick tip for advanced filtering of adjacent sibling nodes.

Given the following HTML:

1
2
3
4
5
6
7
8
<ul>
    <li>Item 1</li>
    <li class=”hello”>Item 2</li>
    <li class=”hello” id=”three”>Item 3</li>
    <li class=”hello”>Item 4</li>
    <li>Item 5</li>
    <li class=”hello”>Item 6</li>
</ul>

If you needed to select the immediate siblings of #three that matched the class .hello (so the resulting element set would be Item 2, Item 3, Item 4) there isn’t an easy way to do this. jQuery provides a prev() and prevAll() methods (as well as their next() counter parts) but that would return all of the elements. Here’s a jQuery immediateSiblings function to take care of this for us:

$(‘#three’).immediateSiblings(‘li.hello’)

Here’s the code for the plugin:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
 * immediateSiblings 1.1.0 (2009-10-19)
 *
 * Copyright (c) 2006-2009 Jonathan Sharp (http://jdsharp.com)
 * Dual licensed under the MIT (MIT-LICENSE.txt)
 * and GPL (GPL-LICENSE.txt) licenses.
 *
 * http://jdsharp.com/
 *
 * Built upon jQuery 1.3.2 (http://jquery.com)
 */
$.fn.immediateSiblings = function(selector) {
    var siblings = [];
    this.each(function() {
        var children = $(this).parent().children(selector).not(this).get();
        $.merge(siblings, children);
    });
    return this.pushStack( $.unique( siblings ) );
};

Cheers,
-Jonathan

Written by jdsharp

July 14th, 2008 at 8:34 pm

Set Focus to the Next Input Field with jQuery

without comments

Setting focus to input fields is easy enough with JavaScript: document.getElementById(‘theInputField’).focus(); but sometimes you need a more generic solution as what happens when the next input field changes ID?

I was recently faced with the problem of setting focus to the next input field. The challenge was that I didn’t know what that field was. So given an input field, find the next logical (in the order of the DOM) input field and set focus. I came up with the following jQuery function (plugin) to accomplish this:

1
2
3
4
5
6
7
8
9
10
$.fn.focusNextInputField = function() {
    return this.each(function() {
        var fields = $(this).parents('form:eq(0),body').find('button,input,textarea,select');
        var index = fields.index( this );
        if ( index > -1 && ( index + 1 ) < fields.length ) {
            fields.eq( index + 1 ).focus();
        }
        return false;
    });
};

The use is as follows:

$( 'current_field_selector' ).focusNextInputField();

Let’s break this code down some:

$.fn.focusNextInputField = function() {

Start off by adding a new jQuery function/plugin

return this.each(function() {

Given a set of elements (this => jQuery object), iterate over them (we’ll return false which stop iteration after the first element.)

var fields = $(this).parents('form:eq(0),body').find('button,input,textarea,select');

Walk up the DOM tree (parents) until we find either the first form element or reach the body tag. Now find all button,input,textarea and select elements.

var index = fields.index( this );

Find out if our current DOM element (this) is in the jQuery collection. Index will return -1 if it is not.

if ( index &gt; -1 &amp;&amp; ( index + 1 ) &lt; fields.length ) {

See if we have a match and make sure we aren’t the last element

fields.eq( index + 1 ).focus();

Select the next input field ( index + 1 ) and set focus to it.

}
return false;

Return false so we stop iteration after this element. So if you call $(…).focusNextInputField() with multiple elements, it will only set focus to the next input field of the first element.

Good luck & enjoy!

Written by jdsharp

May 27th, 2008 at 4:02 pm

jQuery as an Associative Array – Dynamically calling jQuery functions

without comments

So how many times have you done the following:

1
2
3
4
5
6
var elm = $('.selector');
if ( elm.hasClass('selectedElement') ) {
    elm.removeClass('abc');
} else {
    elm.addClass('abc');
}

One alternative to the above example is to use jQuery’s toggleClass() method, but toggleClass does exactly that, toggles the class without a way for us to know the current state.

So now to the point of this post, accessing a jQuery function using associative array notation. Here’s an example of a typical jQuery operation:

1
2
// Call addClass('abc') on all divs
$('div').addClass('abc');

Here’s the same jQuery operation using associative array notation.

1
2
// Call addClass('abc') on all divs using associative array notation
$('div')['addClass']('abc');

Now the refactored example from the beginning of this post:

1
2
var elm = $('.selector');
elm[ ( elm.hasClass('selectedElement') ? 'remove' : 'add' ) + 'Class' ]('abc');

Here’s some additional links on JavaScript objects as Associative Arrays:

Written by jdsharp

May 15th, 2008 at 2:37 pm

jQuery 1.2.3 Released (Quietly!)

without comments

Written by jdsharp

February 7th, 2008 at 1:41 pm

jQuery Iteration and each()

without comments

There was a recent thread on the jQuery discussion group in that there was a need for looping through a series of elements and dynamically binding an event. An issue was brought up with closures and the arguments for dynamic binding of functions. Brandon Aaron provided an elegant solution that makes use of jQuery’s internal each() function. Let’s jump in!

So here’s a paraphrase of Brandon’s code:

Example 1:
jQuery.each( [0,1,2,3,4], function(index, item){
// Your code
});

At first glance this may look the same as your standard iteration code using each but it differs slightly and that is where the benefit is. Let’s look at using the standard each method on a jQuery object:

Example 2:
$(‘selector’).each(function(index){
// Your code
});

In this example jQuery internally manages the collection (array) of matched elements by the selector.

But, by using jQuery’s internal .each() method (Example 1) we’re able to pass in an arbitrary array in which each item will have the callback executed. An elegant solution to your typical for ( i ) loop. Your callback can accept two arguments: index, item where index is the numerical zero based index in the array of the current item and item is the value of the current array. Also worth noting is that by returning false from you callback you can stop iteration over the array (this is the same as using a break; statement in a for loop).

Happy coding!

Written by jdsharp

February 7th, 2008 at 8:00 am

JavaScript Pretty Date by John Resig

without comments

Once again the JavaScript master is at it with “Pretty Date” to take the unfriendly “2008-01-28T20:24:17Z” and turn it into: “2 hours ago“. Worth a look as it is short and sweet!

http://ejohn.org/blog/javascript-pretty-date/

Written by jdsharp

January 31st, 2008 at 10:30 am

Posted in Code-bits,JavaScript