HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Hide and show columns in an HTML table

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
showcolumnstableandhidehtml

Problem

Codepen Link

I've tried to Google, but there's no library that has an API to toggle table columns when clicked elsewhere on the page, so I've decided to do this:

function deleteColumnOnClick() {

    $('.hide div').click(function() {
        var index = $(this).index();
        $('table thead th').eq(index).toggleClass('hidden');
        var hidden = $('table thead th.hidden')
        $.each(hidden, function() {
            var idx = $(this).index();
            $.each($('table tbody tr'), function() {
                $(this).find('td').eq(idx).hide();
            });
        });

        var visible = $('table thead th:not(.hidden)');
        $.each(visible, function() {
            var idx = $(this).index();
            $.each($('table tbody tr'), function() {
                $(this).find('td').eq(idx).show();
            });                    
        });
    });
}

deleteColumnOnClick();


Is this an awful solution? If yes, how do I refactor it?

Solution

Right now, the relationship between the hide/show "buttons" and the columns is pretty fragile. You're dependent on the buttons being in the same exact order as the columns. If you add or remove a button, the indices stop making sense; you can't rely on the 3rd button always being linked to the 3rd column and vice versa.

I'd suggest giving the buttons (or whatever element you use to hide/show columns) a data-column attribute or something similar to make it explicit that this button controls that column. Similarly, the th cells can carry a data-column attribute or simply an ID to identify them.

For instance:

Hide/show

  
    
      A column
      Another column
      Yet another column
    
  
  ...


Now it's explicit that the button will hide column #column-abc. And it'll simplify the code too, since relationships between things are no longer just assumed or implied.

Secondly, you're (in a sense) trying to both hide and show the column, and just seeing what works. It'd be simpler to just do a hasClass("hidden") check. There are also some jQuery selector magic you can use.

Something like this, for instance:

// global click handler for any element with a "data-column" attribute
$("[data-column]").on("click", function () {
  var button = $(this),                   // the element that was clicked
      header = $(button.data("column")),  // the cell referenced by the button
      table = header.closest("table"),    // the table in which the cell resides
      index = header.index() + 1,         // convert to CSS's 1-based indexing
      selector = "tbody tr td:nth-child(" + index + ")",  // selector for all body cells in the column 
      column = table.find(selector).add(header); // all cells in the column

  // toggle the "hidden" class on all the column cells
  column.toggleClass("hidden");
});


Here's a demo

Code Snippets

<button type="button" data-column="#column-abc">Hide/show</button>

<table>
  <thead>
    <tr>
      <th id="column-foo">A column</th>
      <th id="column-xzy">Another column</th>
      <th id="column-abc">Yet another column</th>
    </tr>
  </thead>
  ...
// global click handler for any element with a "data-column" attribute
$("[data-column]").on("click", function () {
  var button = $(this),                   // the element that was clicked
      header = $(button.data("column")),  // the cell referenced by the button
      table = header.closest("table"),    // the table in which the cell resides
      index = header.index() + 1,         // convert to CSS's 1-based indexing
      selector = "tbody tr td:nth-child(" + index + ")",  // selector for all body cells in the column 
      column = table.find(selector).add(header); // all cells in the column

  // toggle the "hidden" class on all the column cells
  column.toggleClass("hidden");
});

Context

StackExchange Code Review Q#83839, answer score: 9

Revisions (0)

No revisions yet.