0
\$\begingroup\$

You can find a JSFiddle demo of my tabs.

The jQuery tabs work well as intended. However I was asked to include arrows alongside the tabs so readers could navigate through tabs using them instead of the tab titles alone.

So I used:

$("li.tab").click( function() {
  $('#div1').removeClass( 'hide' );
  $('#div2').removeClass( 'hide' );
  $('#div3').removeClass( 'hide' );
  $('#div1').removeClass( 'show' );
  $('#div2').removeClass( 'show' );
  $('#div3').removeClass( 'show' );
} );
$("a.rightarrow1").click( function() {
  $('#div1').addClass( 'hide' );
  $('#div2').addClass( 'show' );
  $('#div2').removeClass( 'hide' );
  $('#div3').addClass( 'hide' );
  $('li.tab2').addClass( 'current' );
  $('li.tab1').removeClass( 'current' );
  $('li.tab3').removeClass( 'current' );
} );
$("a.leftarrow1").click( function() {
  $('#div1').addClass( 'hide' );
  $('#div2').addClass( 'hide' );
  $('#div3').addClass( 'show' );
  $('#div3').removeClass( 'hide' );
  $('li.tab3').addClass( 'current' );
  $('li.tab2').removeClass( 'current' );
  $('li.tab1').removeClass( 'current' );
} );
$("a.rightarrow2").click( function() {
  $('#div1').addClass( 'hide' );
  $('#div2').addClass( 'hide' );
  $('#div3').addClass( 'show' );
  $('#div3').removeClass( 'hide' );
  $('li.tab3').addClass( 'current' );
  $('li.tab2').removeClass( 'current' );
  $('li.tab1').removeClass( 'current' );
} );
$("a.leftarrow2").click( function() {
  $('#div1').addClass( 'show' );
  $('#div1').removeClass( 'hide' );
  $('#div2').addClass( 'hide' );
  $('#div3').addClass( 'hide' );
  $('li.tab1').addClass( 'current' );
  $('li.tab2').removeClass( 'current' );
  $('li.tab3').removeClass( 'current' );
} );
$("a.rightarrow3").click( function() {
  $('#div1').addClass( 'show' );
  $('#div1').removeClass( 'hide' );
  $('#div2').addClass( 'hide' );
  $('#div3').addClass( 'hide' );
  $('li.tab1').addClass( 'current' );
  $('li.tab2').removeClass( 'current' );
  $('li.tab3').removeClass( 'current' );
} );
$("a.leftarrow3").click( function() {
  $('#div1').addClass( 'hide' );
  $('#div2').addClass( 'show' );
  $('#div2').removeClass( 'hide' );
  $('#div3').addClass( 'hide' );
  $('li.tab2').addClass( 'current' );
  $('li.tab3').removeClass( 'current' );
  $('li.tab1').removeClass( 'current' );
} );

It's long, but it works. But can it be made more elegant?

\$\endgroup\$
0
4
\$\begingroup\$

Firstly, the obvious:

Both .addClass and .removeClass can deal with multiple classes at once, so wherever you have something like

  $('#div1').removeClass( 'hide' );
  ...
  $('#div1').removeClass( 'show' );
  ...

you can instead write

  $('#div1').removeClass(['hide', 'show']);

You have a few places where you're just removing the same set of classes from a series of elements. You might consider crafting your selector differently to select them all at once, or at the very least define an intermediate function so that you can write something like

stripClasses(["#div1", "#div2", ...], ['hide', 'show']);

All of this actually seems to be pointless, because if the idea is just to navigate through tabs with arrow buttons, you can use the built-in selected option, both to find out which is currently active and to change it.

The fundamental reason you've got so much complexity in that code block is that you seem to have decided to manually manage all the class changes that go along with moving from one tab to another. You don't actually need to do that.

Something like

$("#tabs").tabs();

$(".left-arrow").click(function () { changeTab("#tabs", -1)});
$(".right-arrow").click(function () { changeTab("#tabs", +1)});

function changeTab(elem, by) {
    var sel = $(elem).tabs("option", "selected");
    var newTab = bounded(0, sel+by, 3);
    $(elem).tabs("option", "selected", newTab);
}

function bounded(lower, num, upper) {
    return Math.min(upper, Math.max(lower, num));
}

should work fine (change the newTab expression to get different behavior, like wrapping, out of it). Just be mindful of your local namespaces and styles.

\$\endgroup\$
3
\$\begingroup\$

I see you are using the jquery tools plugin. You can achieve the functionality you are looking for without having to write any extra javascript by naming the tabs:

<!-- wrap each tab with an <a> and name the tab in the href attribute -->
<ul class="large-tabs">
    <li><h2><a href="#tab1">Tab 1</a></h2></li>
    <li><h2><a href="#tab2">Tab 2</a></h2></li>
    <li><h2><a href="#tab3">Tab 3</a></h2></li>
</ul>

and then simply link your prev/next anchors to the tab href:

<!-- tab 1 -->
<div>
    <p>Tab 1 Text</p>
    <a href="#tab3" class="leftarrow1">&laquo; Prev</a>
    <a href="#tab2" class="rightarrow1">Next &raquo;</a>
</div>

<!-- tab 2 -->
<div>
    <p>Tab 2 Text</p>
    <a href="#tab1" class="leftarrow1">&laquo; Prev</a>
    <a href="#tab3" class="rightarrow1">Next &raquo;</a>
</div>

<!-- tab 3 -->
<div>
    <p>Tab 3 Text</p>
    <a href="#tab2" class="leftarrow1">&laquo; Prev</a>
    <a href="#tab1" class="rightarrow1">Next &raquo;</a>
</div> 

Alternatively, you could use the slideshow plugin with tabs and create one prev and one next button to control all slides.

$("ul.large-tabs")
    .tabs("div.large-panes > div.large-pane")
    .slideshow({
         next: '.next', // element class to use for next
         prev: '.prev' // element class to use for prev
     });

The HTML like so:

<!-- tab "panes" -->
<div class="large-panes">   

  <!-- previous link with class '.prev' -->    
  <a class="prev arrow leftarrow1">&laquo; Prev</a>

  <!-- the div panes -->
  <div class="large-pane"> ... </div>
  <div class="large-pane"> ... </div>

  <!-- next link with class '.next' -->
  <a class="next arrow rightarrow1">Next &raquo;</a>

</div>

Unless the tabs are a fixed height you might not want to use the slideshow plugin.

See the Fiddle

The jquerytools documentation is good with lots of examples. It'd be worth checking out. :) Hope that helps!

\$\endgroup\$
0
\$\begingroup\$

First make some adjustments to the HTML :

  • Give all the arrows class="arrow"
  • Give all the arrows a rel="n" attribute, where n = 1, 2 or 3
  • Give all the li tabs "class=tab"

With these adjustments in place, the jQuery will boil down to a couple of lines :

$("a.arrow").click(function(evt) {
    $('#div' + this.rel).removeClass('hide').addClass('show').siblings("div").addClass('hide');
    $(this).closest("li.tab").addClass('current').siblings(".tab").removeClass('current');
});

untested

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.