4
\$\begingroup\$

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?

\$\endgroup\$
6
\$\begingroup\$

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:

<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>
  ...

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

\$\endgroup\$
  • \$\begingroup\$ Thats beautiful! Way more elegant than mine. \$\endgroup\$ – knitevision Mar 12 '15 at 10:12

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.