Tabs Widget page

Create a tabs widget using your own version of jQuery.

Overview

In this part, we will:

  • Create a $.fn.tabs widget.

Slides

Exercise: $.fn.tabs

The problem

Create a progressively enhanced tabs widget. It will be called like:

$("#breeds, #tech").tabs();

Notice that .tabs() can be called on multiple elements. An independent tabs widget should be created on each element in the collection. The elements in the collection should be <ul> elements with the following structure:

<ul id="tech">
  <li><a href="#canjs">CanJS</a></li>
  <li><a href="#stealjs">StealJS</a></li>
  <li><a href="#donejs">DoneJS</a></li>
</ul>
<div id="canjs">
  <a href="https://canjs.com">CanJS</a>
</div>
<div id="stealjs">
  <a href="https://stealjs.com">StealJS</a>
</div>
<div id="donejs">
  <a href="https://donejs.com">DoneJS</a>
</div>

The <ul> elements will have <li> children which serve as the buttons. Each <li> must contain an <a> element. The <a> element’s href attributes reference the id of a tab element to show when the corresponding <li> button element is clicked.

For example when this <li> is clicked:

<li><a href="#stealjs">StealJS</a></li>

The following tab element should be shown:

<div id="stealjs">
  <a href="https://stealjs.com">StealJS</a>
</div>

Finally:

  • Each <ul> should have tabs added to its className.
  • Each tab element should have tab added to its className.

The following CodePen can be used to complete the exercise.

</div>

<script type="module">
const $ = window.$;

$.fn.tabs = function(){

};

$("#breeds, #tech").tabs()
</script>

What you need to know

  • An Immediately Invoked Function Expression (IFFE) can be used to prevent variables and functions from being added to the global scope:

    (function () {
      function activate(li) {
        // DO STUFF
        return li;
      }
    
      $.fn.tabs = function () {
        // can use activate
        activate();
      };
    })();
    
    // can NOT use activate
    activate(); //-> throws an error
  • The following jQuery functions will be useful:

    • $("#selector") - Get a collection of elements using a CSS selector.
    • $([element]) - Create a jQuery collection from an array of elements.
    • collection.children() - Return a collection of all direct descendants of elements in the source collection.
    • collection.find(selector) - Using a CSS selector, find elements descended from elements in the source collection.
    • collection.addClass(className) - Add a class name to elements in the collection.
    • collection.removeClass(className) - Remove elements in the collection.
    • collection.show() - Show elements in the collection.
    • collection.hide() - Hide elements in the collection.
    • collection.bind(event, handler) - Listen to an event.
    • $.each(collection, cb(i, value) ) - Loop through an array-like collection of elements.

Completed Solution

Click to see completed solution

</div>

<script type="module">
const $ = window.$;

(function(){
  function tabContent(li) {
    return $(li.find("a").attr("href"));
  }

  function activate(li) {
    li.addClass("active");
    tabContent(li).show();
    return li;
  }
  function deactivate(li) {
    li.removeClass("active");
    tabContent(li).hide();
    return li;
  }

  $.fn.tabs = function(){
    this.addClass("tabs");
    return $.each(this, function(i, element) {
      var active,
          $lis = $([ element ]).children();

      $.each($lis, function(i, li) {
        var $li = $([ li ]);
        var $tab = tabContent($li);
        $tab.addClass("tab");

        if (i === 0) {
          active = activate($li);
        } else {
          $tab.hide();
        }
      });

      $lis.bind("click", function(event) {
        deactivate( active );
        active = activate( $([ this ]) );
        event.preventDefault();
      });
    });
  };
})();

$("#breeds, #tech").tabs()
</script>

Previous Lesson: Fn Plugins