Ask Ben: Displaying The Next Hidden Element Using jQuery (Update)
This is just a quick update to my previous post on iterating over an array in jQuery. After I posted the solution this morning, it was mentioned that we might want to update it to allow visible elements to be hidden and then re-shown via the button click. The update to this is small and actually simplifies the code - rather than keeping an internal index of the next item to be shown, we are simply going to show the first hidden element in our jquery stack:
The updated code is as follows:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title>jQuery Data Demo With Iterative Click</title>
<script type="text/javascript" src="jquery-1.3.1.pack.js"></script>
<script type="text/javascript">
// When the document loads, initialize the button.
$(
function(){
var jButton = $( "button" );
// First, hide all the list items.
$( "li" ).hide();
// Hook up the "close" links.
$( "li a" )
.attr( "href", "javascript:void( 0 )" )
.click(
function(){
$( this ).parent().slideUp();
}
)
;
// Now, we are going to bind data to the button.
// Since we want to be able to add/remove the
// elements, we are not going to deal with an
// index. Rather, we are gonna go by the first
// hidden element in the collection.
jButton.data(
"config",
{
Collection: $( "li" )
}
);
// Now that we have our data bound, let's bind
// the click event.
jButton.click(
function( objEvent ){
var jThis = $( this );
// Get the config data out of the button.
var objConfig = jThis.data( "config" );
// Find the first hidden element in the
// jQuery stack.
var jHidden = objConfig.Collection.filter( ":hidden:first" );
// Try to show the hidden one (if none
// were returned, this will simply get
// passed over.
jHidden.slideDown();
// Prevent default event (form submit).
objEvent.preventDefault();
return( false );
}
);
}
);
</script>
</head>
<body>
<h1>
jQuery Data Demo With Iterative Click
</h1>
<form>
<button>Show List Item</button>
</form>
<ul>
<li>
I am list item One. <a>close</a>.
</li>
<li>
I am list item Two. <a>close</a>.
</li>
<li>
I am list item Three. <a>close</a>.
</li>
</ul>
</body>
</html>
The magic sauce here is the way in which we locate the element to show once the button has been clicked:
var jHidden = objConfig.Collection.filter( ":hidden:first" );
The filter() method takes our original collection and returns a sub-collection of elements that match the given selectors. This filter uses two selectors, :hidden, which finds all invisible elements (or Inputs of type=hidden), and :first, which limits the collection to the first match. Now, because jQuery methods are not destructive (meaning that they return a new jQuery stack leaving the original jQuery stack unaltered), we can be sure that this filter does not change our Collection variable in any way. Thanks to this behavior, we can call this filter() method each time the button is clicked and it will always be searching the same master collection.
Want to use code from this post? Check out the license.
Reader Comments
Ben...this is incredible, and so are you. Thank you for everything.
@Kevin,
Glad to help!
This is great!
How would I apply this to two or more seperate lists?
thanx its usefull
This is great!
How would I apply this to two or more seperate lists?
And in 1.3.2?? Do we have to resort to using .filter to get just the elements that have css visibility=hidden?
@Richard,
It depends on what your code is doing I guess. You can always use the :hidden pseudo select in the main selector. I guess, I'm not sure what you're asking?
Hi Ben,
how about rather "close"-links than a "back"-button to slideup the shown-elements? How it would be look? Thank you!
Regards
Bachka