mpasd mpasd - 1 year ago 71
CSS Question

JavaScript - On click on undefined number of elements to toggle multiple elements

I have a table that needs to have an undefined number of rows that should display a set number of elements when clicked (in this case div, because I read that it's the best way to use toggle on tr). Best I could do is make it for an already set number of elements...

jsfiddle.net - This is with the set number of elements.

And this is all I got so far trying to figure it out.

Working js code:

$('.warning').on('click', function(e) {
var $ele = $(this).nextUntil('.warning').find('td > div');
$ele.slideToggle();
});
});


In this case, I need each clicked table row to display three corresponding divs.

Obviously, answer with jQuery but I would appreciate a solution in vanilla js as well.

EDIT: I am sorry, I neglected to mention I want to add a sliding animation. And slideToggle doesn't seem to work...

EDIT2: Marked best answer by Terry.

Changed fiddle to working code.

Answer Source

We can actually greatly simplify your markup for your table rows:

<tr class="hidden">
  <td>
    <div>Hidden.</div>
  </td>
  <td>
    <div>Hidden.</div>
  </td>
  <td>
    <div>Hidden.</div>
  </td>
</tr>

...and use the following logic:

  1. .nextUntil('.warning') to select the trailing <tr> after each .warning element. See the documentation for .nextUntil().
  2. Use .slideToggle() to show/hide elements, without the need to use overly verbose CSS detection

Here is the logic above, written in jQuery:

$('.warning').on('click', function() {
    // Selects all siblings until the next `.warning` <tr>
    var $ele = $(this).nextUntil('.warning').find('td > div');
    $ele.slideToggle();
});

If you only want to target downstream <tr> that has the class hidden (useful in the scenario where there might be other irrelevant <tr>s in the way that you do not want to toggle), you might want to add an optional filter instead:

$('.warning').on('click', function() {
  // Selects all siblings until:
  // 1. the next `.warning` <tr>, and
  // 2. has the class "hidden"
  var $ele = $(this).nextUntil('.warning').filter(function() {
    return $(this).hasClass('hidden');
  }).find('td > div');
  $ele.slideToggle();
});

Of course this means that you get strange stacked borders when hiding elements, because you are technically hiding the table row content, but not collapsing the table rows/cells themselves.

Here is a proof-of-concept example:

$(function() {
  $('.warning').on('click', function() {
    var $ele = $(this).nextUntil('.warning').filter(function() {
      return $(this).hasClass('hidden');
    }).find('td > div');
    $ele.slideToggle();
  });
});
table {
  width: 75%;
  border-collapse: collapse;
}

tr,
td {
  border: 2px solid #AEAEAE;
  padding: 0;
}

td {
  width: 50px;
}

.hidden td div {
  display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table id="mytable">
  <tbody>
    <tr class="warning">
      <td>Click to show</td>
      <td>Name</td>
      <td>Age</td>
    </tr>
    <tr class="hidden">
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
    </tr>
    <tr class="hidden">
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
    </tr>
    <tr class="hidden">
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
    </tr>
    <tr class="hidden">
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
    </tr>
    <tr class="hidden">
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
    </tr>
    <tr class="hidden">
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
    </tr>

    <tr class="warning">
      <td>Click to show</td>
      <td>Name</td>
      <td>Age</td>
    </tr>
    <tr class="hidden">
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
    </tr>

    <tr class="warning">
      <td>Click to show</td>
      <td>Name</td>
      <td>Age</td>
    </tr>
    <tr class="hidden">
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
    </tr>
    <tr class="hidden">
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
    </tr>
    <tr class="hidden">
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
      <td>
        <div>Hidden.</div>
      </td>
    </tr>
  </tbody>
</table>

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download