Where to Discuss?

Local Group

Preface

Goal: Switching to jQuery or Cash, for cleaner javascript.

The Javascript Evolution

Before jQuery, there is mootools that has more capability, but jQuery become more popular then mootools. Both have been a great thing in the past, until come modern web framework, such as Angular, Vue, React and Svelte, then jQuery become obsolete. This article just a historical overview at a glance, how jQuery solve plain javascript issue. You should know how jQuery works, but do not invest too much time on jQuery.

There is however this inscredibly small Cash library, but beware of its limitation.

Examples

For tutorial purpose we need two jQuery layouts:

  1. Simple layout, to explain jQuery.

  2. Enhanced layout, as real live jQuery example.

And then we continue with brief example of Cash

  1. Simple layout.

  2. Enhanced layout.


Simple jQuery Tabs : Structure

Document: HTML Head

We can reuse previous tailwind stylesheet.

  <title>Simple Tabs - jQuery</title>
  <link rel="stylesheet" type="text/css" 
        href="../css/03-tailwind-simple.css">
  <script src="../js/vendors/jquery.min.js"></script>
  <script src="../js/custom/jquery-simple.js"></script>

Document: HTML Body: Tab Headers

The same as unobtrusive plain javascript.

Document: HTML Body: Tab Content

The same as unobtrusive plain javascript.


Simple Tabs: Javascript

The code logic is exactly the same with plain javascript, but with different syntax.

Javascript: DOM Event

This simply by wrapping the codes, inside an event called $(document).ready().

$(document).ready(function() {

  // code here …

});

Javascript: Getting Element from Event

The jQuery has $(this). we can use it as below:

  tabHeaders.on('click', 'div', function (event) {
    const targetName = $(this)[0].dataset.target;
    const colorClass = $(this)[0].dataset.color;

    // ..
  });

Javascript: Initialization

Trigger Default Tab

Selecting default tab can be done by trigger the click event with element containing active class.

$(document).ready(function() {
  const tabHeaders  = $('.tab-headers').first();

  // .. code here

  // Tab Headers: Trigger Default
  $('.tab-headers .active').first().click();
});

Javascript: Handling Headers Event

Method Chaining

The capability to chain series of command is the most powerfull feature in jQuery era.

    // Set all to default setting
    tabHeaders.children('div').each(function(i, el) {
      $(this)
        .removeClass('active')
        .removeClass(el.dataset.color)
        .addClass('bg-gray-700');
    });
    // Except the chosen one
    $(this)
      .addClass('active')
      .removeClass('bg-gray-700')
      .addClass(colorClass);

This is basically the same as:

    // Set all to default setting
    tabHeaders.children('div').each(function(i, el) {
      $(this).removeClass('active')
      $(this).removeClass(el.dataset.color)
      $(this).addClass('bg-gray-700');
    });
    // Except the chosen one
    $(this).addClass('active')
    $(this).removeClass('bg-gray-700')
    $(this).addClass(colorClass);

Now you can see how jQuery, solve the code length of plain javascript.

Javascript: Managing Contents

By selecting the id of the content, we can toggle the visibility.

   const tabContents = $('.tab-contents').first();
  
   // Showing the content
    tabContents.children('div').each(function() {
      $(this).hide();
    });
    $('#'+targetName)
      .show()
      .addClass(colorClass);

Javascript: Complete

As a summary, the complete javascript is here below:

$(document).ready(function() {
  const tabHeaders  = $('.tab-headers').first();
  const tabContents = $('.tab-contents').first();

  // Tab Headers: All Click Events
  tabHeaders.on('click', 'div', function (event) {
    const targetName = $(this)[0].dataset.target;
    const colorClass = $(this)[0].dataset.color;

    // Set all to default setting
    tabHeaders.children('div').each(function(i, el) {
      $(this)
        .removeClass('active')
        .removeClass(el.dataset.color)
        .addClass('bg-gray-700');
    });
    // Except the chosen one
    $(this)
      .addClass('active')
      .removeClass('bg-gray-700')
      .addClass(colorClass);

    // Showing the content
    tabContents.children('div').each(function() {
      $(this).hide();
    });
    $('#'+targetName)
      .show()
      .addClass(colorClass);
  });

  // Tab Headers: Trigger Default
  $('.tab-headers .active').first().click();
});

Preview

It is the same as previous plain javascript.

Each time you click the left tab, the color on the right will be changed.


Enhanced jQuery Tabs: Structure

How about real live component?

Document: HTML Head

We can add the javascript at the beginning. We still can reuse previous stylesheet.

  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Tabs - jQuery</title>
  <link rel="stylesheet" type="text/css" href="../css/04-tailwind-enhanced.css">
  <link rel="stylesheet" type="text/css" href="../css/02-border-radius.css">
  <script src="../js/vendors/jquery.min.js"></script>
  <script src="../js/custom/jquery-enhanced.js"></script>

Document: HTML Body: Tab Headers

We have the third level div. The html is the same as unobtrusive plain javascript.

With additional tab-spacer.

Document: HTML Body: Tab Content

We also have the third level div here. The html is the same as unobtrusive plain javascript.


Enhanced Tabs: Javascript

This is also an enhancement of the previous script. With some additional event, to mimic the mouse hover.

Javascript: Managing Headers

Managing third level div can be done adding bg-white class.

    // Set all to default setting
    tabHeaders.children('div').each(function(i, el) {
      // …
      $(this).children(":first").removeClass('bg-white');
    });
    // Except the chosen one
    // …
     $(this).children(":first").addClass('bg-white');

Javascript: Managing Contents

It is exactly the same with the simple tabs layout. No code is changed here.

Preview

Tabs Component: Enhanced Layout: jQuery

Javascript: Mimic Hover

We can utilize this event:

  • onmouseenter: add class is-hovered, and

  • onmouseleave: remove class is-hovered.

Both can be implemented as below:

  // Tab Headers: All Click Events
  tabHeaders.on('mouseenter', 'div', function (event) {
    const targetName = $(this)[0].dataset.target;
    $('#'+targetName).children(":first").addClass('is-hovered');
  });

  // Tab Headers: All Click Events
  tabHeaders.on('mouseleave', 'div', function (event) {
    const targetName = $(this)[0].dataset.target;
    $('#'+targetName).children(":first").removeClass('is-hovered');
  });

While the tailwind stylesheet has been previously written as:

.tab-headers div.active div:hover   { @apply bg-gray-300; }
.tab-contents div div.is-hovered    { @apply bg-gray-300; }

Preview

Now whenever the mouse hovering the active tabs, we can see something as below:

Tabs Component: Enhanced Layout: jQuery: Hovered

Javascript: Complete Code

As a summary, the complete code presented as below:

$(document).ready(function() {
  const tabHeaders  = $('.tab-headers').first();
  const tabContents = $('.tab-contents').first();

  // Tab Headers: All Click Events
  tabHeaders.on('click', 'div', function (event) {
    const targetName = $(this)[0].dataset.target;
    const colorClass = $(this)[0].dataset.color;

    // Set all to default setting
    tabHeaders.children('div').each(function(i, el) {
      $(this)
        .removeClass('active')
        .removeClass(el.dataset.color)
        .addClass('bg-gray-700')
        .children(":first").removeClass('bg-white');
    });
    // Except the chosen one
    $(this)
      .addClass('active')
      .removeClass('bg-gray-700')
      .addClass(colorClass)
      .children(":first").addClass('bg-white');

    // Showing the content
    tabContents.children('div').each(function() {
      $(this).hide();
    });
    $('#'+targetName)
      .show()
      .addClass(colorClass);
  });

  // Tab Headers: All Click Events
  tabHeaders.on('mouseenter', 'div', function (event) {
    const targetName = $(this)[0].dataset.target;
    $('#'+targetName).children(":first").addClass('is-hovered');
  });

  // Tab Headers: All Click Events
  tabHeaders.on('mouseleave', 'div', function (event) {
    const targetName = $(this)[0].dataset.target;
    $('#'+targetName).children(":first").removeClass('is-hovered');
  });

  // Tab Headers: Trigger Default
  $('.tab-headers .active').first().click();
});

Simple Cash Tabs : Javascript

There are, trade offs.

With the same HTML structure, we can achieve similar things with Cash. But beware that not all Query feature is, available in Cash library.

Sometimes we have to mix with plain javascript. And we should also be more creative with the DOM.

$(document).ready(function() {
  // Tab Headers: All Click Events
  $('.tab-headers > div').on('click', function (event) {
    const targetName = $(this)[0].dataset.target;
    const colorClass = $(this)[0].dataset.color;

    // Set all to default setting
    $('.tab-headers > div').each(function(el, i) {
      $(this)
        .removeClass('active')
        .removeClass(el.dataset.color)
        .addClass('bg-gray-700');
    });
    // Except the chosen one
    $(this)
      .addClass('active')
      .removeClass('bg-gray-700')
      .addClass(colorClass);

    // Showing the content
    $('.tab-contents > div').each(function(el, i) {
      el.style.display = 'none';
    });
    sel = $('#'+targetName);
    sel[0].style.display = 'block';
    sel.addClass(colorClass);
  });

  // Tab Headers: Trigger Default
  const tabHeaders  = $('.tab-headers').first();
  $('.active', tabHeaders)[0].click();
});

This works for small projects.

Enhanced Cash Tabs : Javascript

The same applied with enhanced tabs.

$(document).ready(function() {
  //const tabContents = $('.tab-contents').first();

  // Tab Headers: All Click Events
  $('.tab-headers > div').on('click', function (event) {
    const targetName = $(this)[0].dataset.target;
    const colorClass = $(this)[0].dataset.color;
    
    // Set all to default setting
    $('.tab-headers > div').each(function(el, i) {
      $(this)
        .removeClass('active')
        .removeClass(el.dataset.color)
        .addClass('bg-gray-700')
      $(el.firstElementChild).removeClass('bg-white');
    });
    // Except the chosen one
    $(this)
      .addClass('active')
      .removeClass('bg-gray-700')
      .addClass(colorClass)
    $($(this)[0].firstElementChild).addClass('bg-white');

    // Showing the content
    $('.tab-contents > div').each(function(el, i) {
      el.style.display = 'none';
    });
    sel = $('#'+targetName);
    sel[0].style.display = 'block';
    sel.addClass(colorClass);
  });

  // Tab Headers: All Click Events
  $('.tab-headers > div').on('mouseenter', function (event) {
    const targetName = $(this)[0].dataset.target;
    $($('#'+targetName)[0].firstElementChild).addClass('is-hovered');
  });

  // Tab Headers: All Click Events
  $('.tab-headers > div').on('mouseleave', function (event) {
    const targetName = $(this)[0].dataset.target;
    $($('#'+targetName)[0].firstElementChild).removeClass('is-hovered');
  });

  // Tab Headers: Trigger Default
  const tabHeaders  = $('.tab-headers').first();
  $('.active', tabHeaders)[0].click();
});

Some of this Cash trick, can also be applied to jQuery. There are many ways to do stuff, with jQuery. After all, it is all about creativity.


Conclusion

The issue with this good jQuery era is we have to code the logic. Instead of writing program, we can just declare what-to-do in configuration fashioned. This simplicity is an achievement of the modern web framework. We are going to start with Alpine.js.


What’s Next?

Consider continue reading [ Tabs - JS - Alpine.js (inline) ].