0

I have what I believe is a somewhat basic question about arrays in jQuery, but I'm stumped- what I'd like to be able to do is create a number of arrays of DOM elements, each equal in their index numbers, access their index, and then perform jQuery methods according to that index.

For instance, I would like to perform a click action on member i of the first array, and that i would target the corresponding i of the other array members. So, in the following example, clicking arrayOne[1] would only affect arrayTwo[1] and arrayThree[1], clicking arrayOne[2] would only affect arrayTwo[2], arrayThree[2] and so forth.

I've tried using a "for loop", .each() method, .map() and played with the jQuery.each() method, but nothing is working. Either all key/value members are affected, or only one key/value member is affected. Because I've tried so many things, I'm giving a representative problem set, rather than a specific one, and hopefully this will be sufficient to suss out my problem.

var arrayOne=['.selectorOne_a', '.selectorOne_b', '.selectorOne_c'];

var arrayTwo=['.selectorTwo_a', '.selectorTwo_b', '.selectorTwo_c'];

var arrayThree=['.selectorThree_a', '.selectorThree_b', '.selectorThree_c'];

for(i=0; i<=arrayOne.length-1; i++){ 
     $(arrayOne[i]).click(function(){
          $(arrayTwo[i]).show();
          $(arrayThree[i]).hide();
     });//click
}

I realize a for loop isn't the correct way of doing this, but it's meant as a representative method I've tried...Should be simple, right? I don't know whether this would fall under the rubric of a multidimensional array, hash, what-have-you, so any advice or links to tutorials on navigating these concepts would be greatly appreciated as well. I hope this makes sense, and I'd appreciate any advice given.

Thanks!

7
  • 1
    There is nothing such as a jQuery array; you're describing Javascript arrays created by literal notation, or []. Commented Jul 16, 2012 at 1:29
  • 2
    arrayOne-1 is that what you have or is it arrayOne.length-1? Commented Jul 16, 2012 at 1:30
  • sorry, should be arrayOne.length-1... Commented Jul 16, 2012 at 1:46
  • Don't really understand why you posted that comment, Jared, as I don't state anything about "jQuery array." I realize those are javascript arrays, but they are (hopefully) to be used in conjunction with jQuery methods. Commented Jul 16, 2012 at 1:58
  • Your question title is "jQuery array questions", so that's probably what Jared meant. Anyway, as I mentioned in my answer, this whole approach of storing selectors in arrays and trying to relate them to each other is likely not the best way to go about this. If you could show a sample of your html we could advise a better solution. Also, I get the impression you are using classes to identify individual elements - that's what ids are for (using id is both more semantically correct and more efficient). Commented Jul 16, 2012 at 2:04

4 Answers 4

1

Within the click handlers that you are creating you're referencing a variable i that is defined outside the function and by the time the handler is called in reponse to a click i will be whatever is was at the end of the for loop rather than referencing the appropriate related element. You can fix this by introducing a closure:

for(i=0; i < arrayOne.length; i++){
   (function(i){
      $(arrayOne[i]).click(function(){
          $(arrayTwo[i]).show();
          $(arrayThree[i]).hide();
      });
   })(i);
}

When a JS function runs it has access to the variables in its containing scope even when that containing scope is a function that has already finished executing. So the anonymous function I've introduced above is called on each iteration of the for loop and its i parameter remains accessible to the function you were passing to .click().

(Note also your for condition should be i < arrayOne.length, not i<=arrayOne-1 - you can't subtract 1 from an array.)

Since you are using jQuery you can do this in a tidier manner:

$.each(arrayOne, function(i,val) {
     $(arrayOne[i]).click(function(){
          $(arrayTwo[i]).show();
          $(arrayThree[i]).hide();
     });
});

In my opinion a better solution overall would be to dump the idea of using arrays. Relate the elements within your html structure somehow and then use DOM traversal methods within your click handler to find the related elements to show and hide. If you updated your question to show your approximate html structure I could advise further on this.

Sign up to request clarification or add additional context in comments.

3 Comments

Maybe with rel="related-el" or data-sibling="sibling-id-value". I agree, seems silly to use class values like this.
Thanks, nnnnnn! As I mentioned, I'm using your $.each method with success. The reason for using arrays was simplicity- I'd like to be able to quickly add elements to the arrays (their member numbers will always be equal) and then have one method to handle any number of additions, rather than adding them somewhere within the method, or creating a number of different methods, or a switch case scenario, etc... If you'd care to address my error in coding logic on this, I'm all ears.
Are the _a elements related to each other in your html structure in the same way that the _b elements are related to each other? I would assume so since you perform the same click processing on each group of related elements. If so you don't need the arrays because you can use DOM traversal methods (jQuery makes this really easy), and if you add more elements to your html then your JS would pick them up automatically without need to modify any arrays.
0

I think to in that case you can also use other way to achieve your target. You can find out their index value and use to target that for correspond divs.

See a simple Demo

<div class="Array1">
    <div class="selectorOne_a">Array1 a</div>
    <div class="selectorOne_b">Array1 b</div>
    <div class="selectorOne_c">Array1 c</div>
</div>
<div class="Array2">
    <div class="selectorTwo_a">Array2 a</div>
    <div class="selectorTwo_b">Array2 b</div>
    <div class="selectorTwo_c">Array2 c</div>
</div>
<div class="Array3">
    <div class="selectorThree_a">Array2 a</div>
    <div class="selectorThree_b">Array2 b</div>
    <div class="selectorThree_c">Array2 c</div>
</div>

Jquery ccode

$(".Array1 div").click(function() {
   index = $(this).index();
   $(".Array2 div:eq("+ index +")").css('background-color','red');//You can do show/hide or add class etc.
   $(".Array3 div:eq("+ index +")").css('background-color','green');
});

1 Comment

This is fine within itself but it's an answer to a different question. This approach cannot be mixed with the var arrayOne=[...]; etc way of specifying jQuery selectors. In the code above, $(this).index() will return an element's index amongst it's siblings in the DOM; it will not recover it's index within arrayOne.
0

This is a rather odd thing to want to do but if it's necessary then your loop approach is certainly viable. However you need to take measures to ensure that the event handler picks up on the correct value of i. As you have written it, the value of i at the time each handler fires will not necessarily be the value of i at the time the handler was put in place.

There are various ways to resolve this issue.

Closures

At each iteration of the loop, form a 'closure' which (a) captures the value of i and (b) returns a function that becomes the actual event handler.

var arrayOne = ['.selectorOne_a', '.selectorOne_b', '.selectorOne_c'];
var arrayTwo = ['.selectorTwo_a', '.selectorTwo_b', '.selectorTwo_c'];
var arrayThree = ['.selectorThree_a', '.selectorThree_b', '.selectorThree_c'];
for(i=0; i<=arrayOne.length-1; i++) {
     $(arrayOne[i]).on('click', function(n) {
          return function() {
              $(arrayTwo[n]).show();
              $(arrayThree[n]).hide();
          }
     })(i);
}

For clarity I have used n in the closure, in place of 'i'. It's maybe more typical, though not as clear, to use i all through.

.data()

You can use jQuery's .data() method to make DOM elements "aware" of their i value.

var arrayOne = ['.selectorOne_a', '.selectorOne_b', '.selectorOne_c'];
var arrayTwo = ['.selectorTwo_a', '.selectorTwo_b', '.selectorTwo_c'];
var arrayThree = ['.selectorThree_a', '.selectorThree_b', '.selectorThree_c'];
for(i=0; i<=arrayOne.length-1; i++) {
     $(arrayOne[i]).data('index', i).on('click', function() {
        var i = $(this).data('index');
        $(arrayTwo[i]).show();
        $(arrayThree[i]).hide();
     });
}

.each()

You can use the jQuery.each() method to form the loop.

var arrayOne = ['.selectorOne_a', '.selectorOne_b', '.selectorOne_c'];
var arrayTwo = ['.selectorTwo_a', '.selectorTwo_b', '.selectorTwo_c'];
var arrayThree = ['.selectorThree_a', '.selectorThree_b', '.selectorThree_c'];
$.each(arrayOne, function(i) {
     $(this).on('click', function() {
        $(arrayTwo[i]).show();
        $(arrayThree[i]).hide();
     });
});

This is probably the simplest approach. Although it looks different, it is actually very similar to forming closures but the detail is looked after by jQuery.

2 Comments

Thanks, Beetroot-Beetroot! Very valuable, and I'm going to look through all of these thoroughly. Any reason you are using $(this).on('click', function(){//etc... versus $(this).click(function(){...});?
@user933101, it's just force of habit. In large scripts, it's convenient sometimes to search for '.on' to find all event handlers, or to search for 'click' to find specific handlers (and triggers). .click(), .mouseenter() etc. give fewer search options.
0

After following nnnnnn's suggestion, here's the final code I used to solve the problem- it works perfectly, and I can modify it as necessary to create similar sections in my markup, which is built for fluid responsiveness. One thing to note is that I couldn't use css sprites to create roll over states, as that would have involved some disadvantageous absolute positioning, so I decided to create the swap image effect in jQuery/javascript.

    function createClick2(){

    // clickElements are the clickable images which trigger all subsequent actions
    var clickElements= ['.subheader_li_header1 img','.subheader_li_header2 img','.subheader_li_header3 img'];

    //once clickElements are clicked, a specific list appears underneath each clickElement member. These lists are class members of the listShow array
    var listShow= ['.subheader_ul_anim1','.subheader_ul_anim2','.subheader_ul_anim3'];

    // when clickElements are hovered over, an image is swapped- this is the imgSwapOver array
    var imgSwapOver=['img/sidebar_create_over.png','img/sidebar_develop_over.png','img/sidebar_design_over.png'];

    //on mouse out, or double tap, (depending on the device) the image is swapped back in.
    var imgSwapUp=['img/sidebar_create_up.png','img/sidebar_develop_up.png', 'img/sidebar_design_up.png'];

    // counter for holding click information
    var clickCount=0;

    $.each(clickElements, function(i,val) {

        $(clickElements[i]).click(function(){ 
            clickCount++;
            if(clickCount==1){          
                $(listShow[i]).show('slow', function(){
                    $(this).css("display","block");
                    $(clickElements[i]).attr("src", imgSwapOver[i]);//concession for mobile browser

                });//show
            }//if
            else if(clickCount==2){
                $(listShow[i]).hide('slow', function(){
                    $(this).css("display","none");
                    });//hide
                $(clickElements[i]).attr("src", imgSwapUp[i]);//concession for mobile browser
                    clickCount=0;
            }//else if
                }).hover(function(){$(clickElements[i]).attr("src", imgSwapOver[i]); },function(){$(clickElements[i]).attr("src", imgSwapUp[i]); 

                });//hover          
    });//each
}//createClick2

1 Comment

Whoops, sorry if this was posted in the wrong spot! Thanks for all the help, and additional comments are always welcome.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.