Ask Ben: Iterating Over An Array In jQuery, One Index Per Click

Posted January 28, 2009 at 9:04 AM by Ben Nadel

Tags: Javascript / DHTML, Ask Ben

Ben, I'm desperate. I've been all over the Internet looking for some clue how to do this: How would I use .each() with .click to have a single button that would iterate through an array, one object at a time, each time it is clicked? I tried something like:

var myarray = [(#div0),(#div1),(#div2)];
$( myarray ).each(
$("#button").click(function(){
$("#"+objValue).slide("slow");
});

But, obviously that doesn't work. I need the one button, to slide one panel at a time, per each click, in succession. Does that make sense?

When I read your question, the first thing that immediately popped into my mind was jQuery's data() method. I discovered the data() method recently and it blew my mind! If you have not seen it before, jQuery's data() method allows us to associate arbitrary data with any of our DOM elements. What I'm thinking is that if we bind an "Index" value and the actual collection of jQuery elements to our button, then we can easily iterate over the collection, one index per click:

 
 
 
 
 
 
 
 
 
 

As seen in the video, each time we click the button, a new item in our unordered list is shown (using slideDown()). The code for this is quite straightforward:

  • <!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();
  •  
  • // Now, we are going to bind data to the button.
  • // This data will include the array of jQuery
  • // elements that we want to show and the index of
  • // the currently selected item.
  • jButton.data(
  • "config",
  • {
  • Index: 0,
  • 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" );
  •  
  • // Check to see if our index it out of
  • // bounds (more items to click).
  • if (objConfig.Index < objConfig.Collection.length){
  •  
  • // Show the current item. When we are
  • // doing this, post-increment the our
  • // item index.
  • $( objConfig.Collection[ objConfig.Index++ ] ).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.
  • </li>
  • <li>
  • I am list item Two.
  • </li>
  • <li>
  • I am list item Three.
  • </li>
  • </ul>
  •  
  • </body>
  • </html>

As you can see in the code, we are associating a "config" structure with our DOM element, the button. Then, whenever the button is clicked, we retreive that associated "config" data and use the contained "Index" and "Collection" data as needed. jQuery is so powerful, I'd be surprised if there wasn't an even easier way to do this; but, this was the first thing that popped into my mind.




Reader Comments

Jan 28, 2009 at 9:30 AM // reply »
4 Comments

You, sir, are the man. This works exactly as I had invisioned it. I'm gonna get the hang of jQuery. Some of it is actually starting to make sense. I've been doing this javascript the long way for so long, it's been difficult to adapt. But, I have to say, the sheer power of jQuery blows me away.

If I wanted to utilize more specifically the IDs of certain objects, instead of the list items, how would I do that?


Jan 28, 2009 at 9:33 AM // reply »
10,640 Comments

@Kevin,

If you wanted to use IDs, you could simply build the Collection element the same way you did in the question:

Collection: [$("#div0"), $("#div1"), $("#div2")]

The only difference now is that each element in the array contains a jQuery object. As such, when you reference later on, you wouldn't need to re-wrap it in the $() method:

$( objConfig.Collection[ objConfig.Index++ ] ).slideDown();

... vs. ...

objConfig.Collection[ objConfig.Index++ ].slideDown();

Notice that the latter does not use the $() before calling .slideDown(). This has to do with the fact that you are using a jQuery stack in the first and standard array in the second.


Jan 28, 2009 at 9:43 AM // reply »
4 Comments

Thank you very much. I'm going to spend a lot of time on your blog. Your articles have been the most productive learning on jQuery I've found. Keep up the good work...


Jan 28, 2009 at 9:54 AM // reply »
10,640 Comments

@Kevin,

Always glad to help. Please feel free to ask me for any demos - it's how I spend my mornings :)


Jan 28, 2009 at 10:36 AM // reply »
4 Comments

Ben,

Now I'm really going to get confusing.

Each of the DIVs in my array have "X" buttons, where I use slideUp() to remove them. If I have iterated through all of the array objects, then remove one or more of the DIVs, how can I "reset" the array so that I can click and add them back, if need?

And, while we're at it, I'd like to reduce the amount of code in my script by passing the ID of the DIV back to the slideUp() function, instead of having a separate function for each one. I do this all the time with long javascript, but not sure how I would accomplish this with jQuery. (Feel free to make this a separate post, if you prefer. I think it could be a useful tutorial on reusing code.)

Thanks,
Kevin


Jan 28, 2009 at 2:55 PM // reply »
10,640 Comments

@Kevin,

Hmm, interesting....


Jan 28, 2009 at 3:23 PM // reply »
10,640 Comments

@Kevin,

Try this:

http://www.bennadel.com/blog/1476-Ask-Ben-Displaying-The-Next-Hidden-Element-Using-jQuery-Update-.htm

The difference here is that you have to use a jQuery stack - you can't just use an array for your collection (since we need to filter on it). You can still add arbitrary elements to the same jQuery stack:

Collection: $("#div0").add("#div1").add("#div2")

Hope that helps.


May 15, 2009 at 11:13 AM // reply »
3 Comments

Hi Ben. Great script. It has very nearly helped me to get exactly what I need. However, I need to tweak it and I just can't get it to work. What I am looking for is a way to hide all but the first three items on load (as opposed to hiding all items). Then I need a way to reduce the number of items back down to a minimum of three. I am trying to reproduce something similar to the BBC home page (bbc.co.uk) where clicking the plus/minus buttons shows/hides additional items. Any help to finish this off would be most appreciated. I can email you the code I have so far if required?


May 19, 2009 at 9:34 AM // reply »
10,640 Comments

@John,

To hide everything after 3rd element, you can use the selector: gt():

$( "div:gt(2)" ).hide()

Since gt() is zero-based, greater than 2 will exclude 0, 1, and 2.


May 19, 2009 at 10:01 AM // reply »
3 Comments

Many many thanks, Ben. I never knew about using :gt in JQuery. That makes things a lot simpler...


Oct 19, 2009 at 2:38 PM // reply »
1 Comments

life saver....

was looking for a simple approach to showing and hiding individual profiles on a click of an anchor. This gave me a massive input.

Thanks


Oct 31, 2009 at 4:47 PM // reply »
10,640 Comments

@errol187,

Awesome :)


Post A Comment

Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.

Please review the following issues:

Author Name:


Author Email:

Author Website:

Comment:

Supported HTML tags for formatting: <strong>bold</strong>   <em>italic</em>   <code>code</code>







  • Help Wanted - Find Your Next ColdFusion Job
InVision App - Prototyping Made Beautiful With Prototyping Tools Ben Nadel's Company - Epicenter Consulting Recent Blog Comments
Feb 10, 2012 at 7:21 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
Update! Instead of $(eval(options.insertAfter)).after(data['insertData']); I now use: var ajaxNode = document.createElement('span'); var parent = $(eval(options.insertAfter))[0].parentNode; ... read »
Feb 10, 2012 at 6:18 PM
jQuery AJAX Strips Script Tags And Inserts Them After Parent-Most Elements
encountered this same, what I consider, jQuery bug last week. I'm building a site in which I load some content via AJAX. This content contains Linkedin share button placeholders which Linkedin API ne ... read »
Feb 10, 2012 at 11:30 AM
Cross-Origin Resource Sharing (CORS) AJAX Requests Between jQuery And Node.js
After you understand the concepts here, this is an awesome cheatsheet for enabling CORS in just about anything http://enable-cors.org/ ... read »
JM
Feb 10, 2012 at 9:10 AM
My Safari Browser SQLite Database Hello World Example
@Amy, Here is a very good tutorial on how to use JOIN: http://www.sqltutorial.org/sqljoin-innerjoin.aspx ... read »
Feb 10, 2012 at 4:42 AM
Building A Twitter-Inspired RESTful API Architecture In ColdFusion
This is great, very useful Ben. I spotted a small typo in the api.cgm listing: <cfthrow type="Unauthroized" /> Cheers Stefan ... read »
Feb 9, 2012 at 10:35 PM
CFDirectory Filtering Uses Pipe Character For Multiple Filters (Thanks Steve Withington)
I was wondering if there would be a filter you could apply so that you got everything but what you included in the filter. As in show me all docs that are not a .pdf. ... read »
Feb 9, 2012 at 10:29 PM
Learning ColdFusion 9: Application-Specific Data Sources
@Ben, No offence, but if people were really wanting advanced features they would be using a platform like ASP.NET MVC. CFML is so structurally compromised as a tag-based scripting language that ... read »
Feb 9, 2012 at 10:03 PM
Subversion - Cleanup Failed To Process The Following Paths
@Leviaguirre, do you still have problems with this? ... read »