ak85
ak85

Reputation: 4264

Most Efficient Wyt to use Multiple .click in jQuery

I have a simple form which works as intended. It is a multi-step form that only shows one question at a time. When the user clicks on an input field (all radio buttons) they get taken to the next question, which is different depending on what they clicked and then finally they get a submit button after the last question.
I currently have several .click functions, and this works well. However, I am sure it is not the most efficient way to do this, in terms of both writing and performance. Is there a more efficient way to use multiple .click functions?

$('.male').click(function() {
  $('#male').show();
  $('#gender').hide();
});

$('.female').click(function() {
  $('#female').show();
  $('#gender').hide();
});

Upvotes: 1

Views: 176

Answers (4)

JKirchartz
JKirchartz

Reputation: 18022

due to event bubbling you could do this:

​$('body').on('click',function(e){
    switch ($(e.target).attr('class')){
        case "male":
            $('#male').show();
            $('#gender').hide();
            break;
        case "female":
            $('#female').show();
            $('#gender').hide();
            break;
        default:
            alert("default function!");
            break;            
    }
});​​​​​​

here's a demo: http://jsfiddle.net/748sE/2/

of course the default function will return on anything you click on that page that isn't already caught...

BTW, you can replace $(e.target).attr('class') with e.target.className to optimize it a bit, as David Thomas did in his answer...

Upvotes: 1

David Thomas
David Thomas

Reputation: 253328

Assuming a logical structure to your HTML, such as:

<form action="#" method="post">
    <fieldset>
        <legend>Question 1: gender</legend>
        <label for="m">Male</label>
        <input type="radio" name="gender" id="m" />
        <label for="f">Female</label>
        <input type="radio" name="gender" id="f" />
    </fieldset>
    <fieldset>
        <legend>Question title</legend>
        <!-- answer options -->
    </fieldset>
    <!-- other questions... -->
</form>

Then the simplest option I can think of is the following:

$('form').on('click','input',
              function(){
                  var fieldset = $(this).closest('fieldset');
                  fieldset.fadeOut(500,
                      function(){
                          fieldset.next('fieldset').fadeIn(500);
                      });
              });​

JS Fiddle demo.

To allow for revisiting previous questions, I'd suggest an adaptation along the following lines:

<form action="#" method="post">
    <fieldset>
        <legend>Question 1: gender</legend>
        <label for="m">Male</label>
        <input type="radio" name="gender" id="m" />
        <label for="f">Female</label>
        <input type="radio" name="gender" id="f" />
        <div class="controls">
            <a href="#" class="prev">Previous</a>
            <a href="#" class="next">Next</a>
        </div>
    </fieldset>
    <!-- other questions... -->
</form>

And coupled with the jQuery:

$('fieldset').not($('fieldset:eq(0)')).hide();
$('.controls a.prev:first, .controls a.next:last').addClass('disabled');
$('form').on('click', 'input, a', function(e) {
    var target = e.target,
        targetType = target.tagName.toLowerCase(),
        targetClass = target.className,
        fieldset = $(this).closest('fieldset'),
        prev = fieldset.prev().length,
        next = fieldset.next().length;

    if (targetType == 'input' && next > 0) {
        fieldset.fadeOut(500, function() {
            fieldset.next('fieldset').fadeIn(500);
        });
    }
    else if (targetType == 'a') {
        if (targetClass == 'prev' && prev > 0) {
            fieldset.fadeOut(500, function() {
                fieldset.prev('fieldset').fadeIn(500);
            });
        }
        else if (targetClass == 'next' && next > 0) {
            fieldset.fadeOut(500, function() {
                fieldset.next('fieldset').fadeIn(500);
            });
        }
    }
});​

JS Fiddle demo.

References:

  1. jQuery stuff:

  2. Native JavaScript stuff:

Upvotes: 3

veeTrain
veeTrain

Reputation: 2915

You could give all of the questions the class of 'question' and then each answer could have an id corresponding to a class (or other) property of the upcoming branch you wanted to display.

Therefore each response would hold the name for what to display next for you and you would be able to only have one click handler.

I.e.:

$("input").click(function() {
    $(".question").hide();
    var itemToShow = $(this).attr("id");
    //alert(itemToShow);
    if ($("."+itemToShow).length > 0) {
        $("."+itemToShow).show("normal");
    } else {
        $(".finale").show("normal");
    }
});

You'll probably need to play around with it a little bit until the control works as you'd like. Here's a fiddle to work off of.

Update: Here's the latest fiddle demonstration.

Upvotes: 0

Rory McCrossan
Rory McCrossan

Reputation: 337580

Because both of your #male and #female elements require code to run when they are clicked on they both need their own click handler. However, you could simplify this code by including them both in the same selector and calling a single function to handle them both. Try this:

$(".male, .female").click(showDivs);

function showDivs() {
    if ($(this).hasClass("male")) {
        $("#male").show();
    }
    else {
        $("#female").show();
    }
    $("#gender").hide();
}

Upvotes: 0

Related Questions