tags:

views:

67

answers:

6

I have the following code which processes a click from a tab and loads contents via ajax:

$(document).ready(function()
{
    $("#tab1").click(function()
    {
        loadTab($(this).attr("href") + "?ajax=1");
        return false; // cancel the event
    });

    $("#tab2").click(function()
    {
        loadTab($(this).attr("href") + "?ajax=1");
        return false; // cancel the event
    });

    $("#tab3").click(function()
    {
        loadTab($(this).attr("href") + "?ajax=1");
        return false; // cancel the event
    });

    $("#tab4").click(function()
    {
        loadTab($(this).attr("href") + "?ajax=1");
        return false; // cancel the event
    });
});

You'll notice that there are lots of repeated code.

Is there any way of grouping the #tab1, #tab2, .... into a single .click(function() ?

+8  A: 
$(document).ready(function()
{
    $("#tab1, #tab2, #tab3, #tab4").click(function()
    {
        loadTab($(this).attr("href") + "?ajax=1");
        return false; // cancel the event
    });
});

edit to add some value to the answer (see also other answers, which already mention some, maybe even all, of the following):

  • you should give the tabs a common identifier, such as a css class: abstraction is good, mmkay?

    $(document).ready(function()
    {
        $(".tab").click(function()
        {
            loadTab($(this).attr("href") + "?ajax=1");
            return false;
        });
    });
    
  • the tabs are likely to have a common ancestor not too far above. like, they're all (inside) <li>'s within a single <ul>. explore that and use event delegation.

    $(document).ready(function()
    {
        $("#tabs").click(function(e)
        {
            if (!$(e.target).is('.tab')) return;
            loadTab($(this).attr("href") + "?ajax=1");
            return false;
        });
    });
    
  • use the delegate API added in 1.4.2 to spare the guard clause:

    $(document).ready(function()
    {
        $("#tabs").delegate('.tab', 'click', function()
        {
            loadTab($(this).attr("href") + "?ajax=1");
            return false;
        });
    });
    
  • no need to get overzealous with jquery application:

    $(document).ready(function()
    {
        $("#tabs").delegate('.tab', 'click', function()
        {
            loadTab(this.href + "?ajax=1");
            return false;
        });
    });
    
just somebody
+1 Or if they have some other thing in common you can query via CSS selector (they all have the same class, they're all direct children of a tab container, they all have an attribute called `data-foo`, etc.), you can use that instead of a list of IDs, making things a bit more maintainable. For instance, if they're all `class="tab"` and nothing else is, `$(".tab").click(...`; or if they're all inside a `<div id="tabContainer">` and the only things with IDs starting with "tab": `$('#tabContainer *[id^=tab]').click(...`.
T.J. Crowder
Thanks, that's exactly the way I decided to go since all are direct children of a tab container. I was just using code from a example and was complicating more than I should.
smartins
+1  A: 

Or, give all the tab item the same CSS class and then do

$(".classname").click(...);

In this way, even if you add new tabs your code will still automagically work :)

nico
Thanks, that was the way I decided to go.
smartins
A: 

if you give all the tabs a class, say ".tabs" you could do this:

    $(".tabs").each(function(){

       $(this).bind('click', function(){

           loadTab($(this).attr("href") + "?ajax=1");
            return false; // cancel the event
      })

    });

no sure i'ts the most optimized way to go, but it should work.

Nils
ok, so that was stupid. you dont need the each-part... were's my head today.
Nils
well, not "stupid" but sub-optimal I would agree :)
Mark Schultheiss
+1  A: 

I would suggest the following alternatives:

  • live: give your tabs a certain css class and select on that: $('.tabClass').live('click', function() {// dosomethinguseful});
    The reason to go for live instead of click could be that there could be made extra tabs on the fly. Live handles this for you automatically.
  • Make use of jQueryUI tabs control. Easy to use and it has ajax capability baked in.
XIII
or use .delegate() which has some performance benifits
Mark Schultheiss
+1  A: 

As an alternative you can delegate a single click event to do different things depending on the target of the click (known as event delegation)

Markup:

<div id="tabs">
    <a href="#1">Tab 1</a>
    <a href="#2">Tab 2</a>
    <a href="#3">Tab 3</a>
    <a href="#4">Tab 4</a>
</div>

JavaScript:

$("#tabs").click(function(e)
{
    e.preventDefault();
    var target = $(e.target);
    if(target.is("a")) {
        alert(target.attr("href") + "?ajax=1");
    }
});

There is a shortcut function to do this in jQuery called .delegate(), a bit redundant imo, but worth checking out.

Daniel
+1  A: 

You can use multiple selectors in jQuery by comma-delimiting, as another answer has already pointed out. However, I wanted to point out another way to share code that, although it does not really apply in this particular case, it is good knowledge to have. Say you had multiple events that needed the use the same function. A cool thing about Javascript is that functions can be stored as a variable and then re-used...

var func = function(e) { 
  loadTab($(this).attr("href") + "?ajax=1");
  e.preventDefault(); // proper way to cancel the event
  return false; // cancel the event 
}

$("#tab1,#tab2,#tab3,#tab4").click(func);

Like I said, it doesn't have any benefits in this particular case, but there are times that you need to use the same function for multiple events.

Josh Stodola