1

Think this is a chicken-or-egg or closure problem or something else I'm missing. How do I loop through numerical selector values in JQuery when there is an onClick event handler?

$("#q01").click(function() {
    clearIt();
    $("#item01").show();
}); 
$("#q02").click(function() {
    clearIt();
    $("#item02").show();
});
$("#q03").click(function() {
    clearIt();
    $("#item03").show();
});
4
  • you have id of all of them in same way q01 after q02 Commented Apr 12, 2013 at 19:23
  • Are you trying to trigger the handler? Or just select only those elements with a click handler attached? Commented Apr 12, 2013 at 19:25
  • Trying to trigger the handler - thank you. Commented Apr 12, 2013 at 20:07
  • So you're trying to simulate someone clicking on it? If so, try the "Edit 2" section in my answer. I think everyone assumed you were trying to fix your event-binding code, including me. Commented Apr 12, 2013 at 21:05

6 Answers 6

4

You might want to try this:

$("[id^=q]").each(function () {
    $(this).click(function () {
        clearIt();
        var id = this.id.replace(/[^\d]/g, ''); 
        $("#item" + id).show();
    });
});
Sign up to request clarification or add additional context in comments.

2 Comments

Like this one the best... +1 -- Nice regex.
Why [^\d.] instead of [^\d]?
2

It's hard to say exactly, since your example is probably simplified. But try a more general selector, rather than selecting them by ID (you can use $('[id^="q"]'), but that's not really best practice). You're using the ID element like a class, which isn't really what id is for.

If you give them all a class attribute like class="q" for the buttons and class="item" for the targets, you can do something like this:

$('.q').each(function(index) {
    var targetItem = $('.item').eq(index);
    $(this).click(function() {
        clearIt();
        targetItem.show();
    });
});

But it'll be easier, safer, and better practice to specify the target of each clickable element right there in the markup:

<a href="#" class="p" target-index="01">p01</a>
<a href="#" class="p" target-index="02">p02</a>

<div class="item" item-index="01">item01</div>
<div class="item" item-index="02">item02</div>

Then their order and location on the page won't matter. You can just select them directly:

var num = $(this).attr('target-index');
var targetItem = $('.item[item-index="' + num + '"]');

Finally (and my preferred advice), you can put the ID of the target right into the button itself:

<a href="#" class="p" for="item01">p01</a>
<div id="item01">item01</div>

Then you can select the target quickly, safely, and regardless of its location:

var targetItem = $('#' + $(this).attr('for'));

Edit 1:

My first snippet makes assumptions about the order of your elements, because there are lots of ways for the clicked element to be associated with the target item. Only you know the rules for your markup, so only you know what assumptions will work. For example:

var targetItem = $('#' + $(this).attr('id').replace(/^q/, 'item'));
var targetItem = $(this).siblings('[id^="item"]');
var targetItem = $(this).children('[id^="item"]');
var targetItem = $(this).parents('[id^="item"]');
var targetItem = $(this).find('[id^="item"]');

If you don't use the target-index technique I suggested, you'll have to make at least some assumptions based on your knowledge of the HTML.


Edit 2:

Based on your comment that you're trying to trigger the handlers, rather than improve your event-binding code, you can do that like this:

//quick and dirty zero-padding function from http://stackoverflow.com/q/10073699/399649
var pad = function(num, size) {
  return (Math.pow(10, size) + ~~num).toString().substring(1);
};
for(var i = 1; i < $('[id^="q"]').length; i++) {
    var index = pad(i, 2);
    $('#q' + index).trigger('click');
}

1 Comment

+1 For providing the best-practice solution :)
1

You can utilize jquery starts with selector. While using a starts with selector it always advised to use a context within the elements reside. But you can also use a class name for the buttons and bind it with click event with single selector.

$('[id^=q]','çontext').click(function(){...}

or

$('input.classSelector',context).click(function(){...})

With Id Selector

http://jsfiddle.net/Beffv/

function clearIt()
{
$('[id^=item]','#section').hide();
}
clearIt();
$('[id^=q]','#section').click(function(){

    clearIt();
  $('#item' + $(this).attr('id').replace('q',''),'#section').show();
});

With Class Selector

http://jsfiddle.net/vrVcL/

Html

<div id="section">
<input id="q01" type="button" class="itemBtn" value="q1"/>
<input id="q02" type="button" class="itemBtn" value="q2"/>
<input id="q03" type="button" class="itemBtn" value="q3"/>

<div id="item01" class="itemDiv">test</div>
<div id="item02" class="itemDiv">test2</div>
<div id="item03" class="itemDiv">test3</div>
</div>

Script

    function clearIt()
{
$('.itemDiv','#section').hide();
}
clearIt();
$('.itemBtn','#section').click(function(){
    clearIt();
    $('.itemDiv:nth-of-type(' + parseInt($(this).attr('id').replace('q','')) + ')','#section').show();
});

12 Comments

@Roasted, @Palash - And what if he has an element <button id="queueItem" /> or some other element with an id starting with q?
You need to give a context
Specify that in your answer, then
+1 for being the first to suggest the selector and the only one to specify that it must have a context! This is the best answer because of the explanation! Combine it with @PalashMondal's string replace and it is perfect!
@JustinMorgan if you are using a class selector and you know that you are using these class names uniquely for a purpose, yes there is no need for context. But it is always safe to use a context. Context doesn't mean that you need to wrap them. This is just in the example where it is wrapped. In the original html wrapper could be the actual wrapper used for a section itself. My exaple with class is different it just uses the nth-type-of selector again. if i had such a req i would definitely have gone with a class selector than id.
|
0

You can use jquery each():

SEE DEMO

$('[id^=q0]').each(function (i) {
    ++i;
    $(this).click(function () {
        $('#item0' + i).show();
    });
});

4 Comments

what if, in the markup, <div id="q03">Click</div> is present before <div id="q01">Click</div>?
@Justin Morgan same thought.
@Ejay - My code is an example. I can't see the HTML, so I made assumptions about its structure. In fact, there are lots of ways to do this, but finding the right target requires making some kind of assumption about it. See my edit.
right :) I just wanted to point out that relying on index isn't robust
0

javascript

        var items= $('.item');
        $('.btn').click(function(){
           var num = $(this).attr('id').match(/\d+/ig)
           var item = $('#item'+num[0]+'.item');
           if(item.length){
              clearIt();
              item.show();
           }
        })

        function clearIt(){
           items.hide();
        }

markup

     <a id="q01" href="#" class="btn">Q01</a>
     <a id="q02" href="#" class="btn">Q02</a>
     <a id="q03" href="#" class="btn">Q03</a>

     <div id="item01" class="item">Item 01</div>
     <div id="item02" class="item">Item 02</div>
     <div id="item03" class="item">Item 03</div>

This way you could add and remove the show/hide toggling by simply removing the class .btn or .item.

Comments

0

You should try data- attributes. In this way, you don't need any string replacement. Just keep the target's id in a data attribute, in this example I use data-target. You can change to any name you like. data-show , data-blah.

HTML

<button type="button" class="clear-it" data-target="item01">Clear it and 
show the target</button>

JavaScript

$('.clear-it').each(function() {
  clearIt();
  $(this).click(function() {
    var whereToGo = this.getAttribute('data-target');
    // or var whereToGo = this.dataset.target;
    // or var whereToGo = $(this).data('target');

    $("#" + whereToGo).show();
  });
})

Comments

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.