0

jQuery.fn.areAll = function(arg) {
  return this.get().every(function(e) {
    return $(e).is(arg);
  });
};

$(document).ready(function() {

  function hidden_all() {

    if ($('.hidden_1, .hidden_2, .hidden_3').areAll(':visible')) {
      $(".togglehidden_all").removeClass("show").addClass("hide");
    } else if ($('.hidden_1, .hidden_2, .hidden_3').areAll(':hidden')) {
      $(".togglehidden_all").removeClass("hide").addClass("show");
    }
  }

  $(".hidden_all").click(function() {

    if ($(".hidden_1, .hidden_2, .hidden_3").areAll(":visible")) {
      $(".togglehidden_all").removeClass("show").addClass("hide");
    } else if ($(".hidden_1, .hidden_2, .hidden_3").areAll(":hidden")) {
      $(".togglehidden_all").removeClass("hide").addClass("show");
    }
  });

  $(".togglehidden_all").click(function() {

    if ($(".hidden_1, .hidden_2, .hidden_3").areAll(":visible")) {
      $(".hidden_1, .hidden_2, .hidden_3").slideUp("slow");
      $(".togglehidden_1, .togglehidden_2, .togglehidden_3").removeClass("show").addClass("hide");
      $(".togglehidden_all").removeClass("hide").addClass("show");
    } else {
      $(".hidden_1, .hidden_2, .hidden_3").slideDown("slow");
      $(".togglehidden_1, .togglehidden_2, .togglehidden_3").removeClass("hide").addClass("show");
      $(".togglehidden_all").removeClass("show").addClass("hide");
    }
  });

  $(".togglehidden_1").click(function() {

    if ($(".hidden_1").is(":visible")) {
      $(".hidden_1").slideUp("slow");
      $(".togglehidden_1").removeClass("show").addClass("hide");
      hidden_all();
    } else {
      $(".hidden_1").slideDown("slow");
      $(".togglehidden_1").removeClass("hide").addClass("show");
      hidden_all();
    }
  });

  $(".togglehidden_2").click(function() {

    if ($(".hidden_2").is(":visible")) {
      $(".hidden_2").slideUp("slow");
      $(".togglehidden_2").removeClass("show").addClass("hide");
      hidden_all();
    } else {
      $(".hidden_2").slideDown("slow");
      $(".togglehidden_2").removeClass("hide").addClass("show");
      hidden_all();
    }
  });

  $(".togglehidden_3").click(function() {

    if ($(".hidden_3").is(":visible")) {
      $(".hidden_3").slideUp("slow");
      $(".togglehidden_3").removeClass("show").addClass("hide");
      hidden_all();
    } else {
      $(".hidden_3").slideDown("slow");
      $(".togglehidden_3").removeClass("hide").addClass("show");
      hidden_all();
    }
  });

});
.show {
  color: white;
  background-color: green;
}

.hide {
  color: white;
  background-color: red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<table>
  <tbody>
    <tr>
      <td class="togglehidden_all">+/-</td>
    </tr>
    <tr>
      <td class="togglehidden_1">1</td>
    </tr>
    <tr>
      <td class="hidden_1">2</td>
    </tr>
    <tr>
      <td class="togglehidden_2">3</td>
    </tr>
    <tr>
      <td class="hidden_2">4</td>
    </tr>
    <tr>
      <td class="togglehidden_3">5</td>
    </tr>
    <tr>
      <td class="hidden_3">6</td>
    </tr>
    <tr>
      <td class="hidden_all">hidden_all click function Test</td>
    </tr>
  </tbody>
</table>

Note : Click the "+/-" first to give initial classes for this example.

Clicking on "+/-" shows/hides divs 2, 4 and 6 all together Clicking on div1 toggles show/hide div2 Clicking on div3 toggles show/hide div4 Clicking on div3 toggles show/hide div4

When div1, div2, and div3 are all opened one by one the "+/-" updates to the hide class (red). However, when they are all closed one by one it does not update to the show class (green). Ie it does not work in reverse strangely

(It will update correctly if I run the function manually via $(".hidden_all").click(function() i.e. clicking on "hidden_all click function Test". As such I tried triggering this function from within the other functions but it had no effect on the problem).

Thanks in advance.

Guruprasad J Rao
  • 29,410
  • 14
  • 101
  • 200
Sach
  • 75
  • 1
  • 10
  • 1
    That is because when you are calling `hidden_all`, the animation of `hidden_x` element won't be completed, so the `areAll` check is going to fail – Arun P Johny Mar 06 '17 at 03:57
  • Thank you. That was my guess. Would this type of implementation work [link] http://stackoverflow.com/questions/1065806/how-to-get-jquery-to-wait-until-an-effect-is-finished [/link] – Sach Mar 06 '17 at 04:48
  • Works great ... for all animations. Thanks – Sach Mar 06 '17 at 05:15

3 Answers3

0

LEFT THIS answer IN for ORIGINAL markup.

I found your code somewhat busy, forgive me for that so I reworked it a bit. I also put the animation in a function to make it easier to call.

$(document).ready(function() {
  var allthem = $('.hidden_1, .hidden_2, .hidden_3');

  function hidden_all() {
    $(".togglehidden_all")
      .toggleClass("show", allthem.areAll(':visible'))
      .toggleClass("hide", allthem.areAll(':hidden'));
  }
  jQuery.fn.areAll = function(arg) {
    return this.get().every(function(e) {
      return $(e).is(arg);
    });
  };
  jQuery.fn.slideToggleBool = function(bool, options) {
    return bool ? $(this).slideDown(options, hidden_all) : $(this).slideUp(options, hidden_all);
  };
  $(".hidden_all").click(function() {
    hidden_all();
  });
  $(".togglehidden_all").click(function() {
    var isall = allthem.areAll(":visible");
    allthem.slideToggleBool(!isall, "slow");
    $(".togglehidden_1, .togglehidden_2, .togglehidden_3")
      .toggleClass("show", isall)
      .toggleClass("hide", !isall);
  });
  $(".togglehidden_1, .togglehidden_2, .togglehidden_3").on('click', function() {
    // to keep ref inside the done where "this" is the animating one
    var me = $(this);
    $(this).closest('tr').next('tr').find('td').promise().done(function() {
      // will be called when all the animations on the queue finish
      var isVis = $(this).is(":visible");
      me.closest('tr').next().slideToggleBool(!isVis, "slow");
      me.toggleClass("show", !isVis).toggleClass("hide", isVis);
    });
  });
});

I also further made the last 3 functions one reworked that to find a relatively positioned element from the one clicked. Note the if you clicked quickly on the elements (single) they would also have issues with the toggle, the animation on that one not completing. This also should address that in that last function.

I did minimal testing to check for other issues.

Mark Schultheiss
  • 32,614
  • 12
  • 69
  • 100
  • Thanks for the effort. I am learning jQuery so this looks useful, but sadly it does not work correctly when clicking on the sub toggles. – Sach Mar 07 '17 at 22:34
  • Not 100% sure of your requirement, but here is a fiddle that does "something" with this https://jsfiddle.net/MarkSchultheiss/ud99cf0u/ Note that this was built only based upon your original markup. – Mark Schultheiss Mar 08 '17 at 16:22
  • As before, this code doesn't work as expected unfortunately. The all toggle class changes incorrectly or has no class when clicking toggle 1, 2 or 3. It should work as per my working example but there are somethings I can learn from your example. Thanks – Sach Mar 08 '17 at 23:47
0

This is my working code.

If you are able to simplify that would be great. Ideally I would like the sub toggles to open/close all rows between sub toggles. Also some sort of counter that will work with any number of sub toggles to flip the main toggle if a % of the sub toggles are either hidden or visible.

Thanks

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>

jQuery.fn.areAll = function(arg) {
    return this.get().every(function(e) {
        return $(e).is(arg);
    });
};

$(document).ready(function(){

var $allhidden = $(".hidden_1, .hidden_2, .hidden_3");
var $subtoggles = $(".togglehidden_1, .togglehidden_2, .togglehidden_3");

function hidden_all(){

  if    ($allhidden.areAll(":visible")){
           $(".togglehidden_all").removeClass("show").addClass("hide");}

        else {
           $(".togglehidden_all").removeClass("hide").addClass("show");}
}

    $(".togglehidden_all").click(function(){
    
  if   ($allhidden.areAll(":visible")){
       $allhidden.slideUp("slow");
                    $subtoggles.removeClass("hide").addClass("show");
                    $(".togglehidden_all").removeClass("hide").addClass("show");}
  else  { 
                    $allhidden.slideDown("slow");
           $subtoggles.removeClass("show").addClass("hide");
                    $(".togglehidden_all").removeClass("show").addClass("hide");}
});

    $(".togglehidden_1").click(function(){
    
  if   ($(".hidden_1").is(":visible"))
           { $(".hidden_1").slideUp("slow", function(){
                      $(".togglehidden_1").removeClass("hide").addClass("show");
                        hidden_all();})}
                
  else   { $(".hidden_1").slideDown("slow", function(){
            $(".togglehidden_1").removeClass("show").addClass("hide");
                        hidden_all();})}                      
});

    $(".togglehidden_2").click(function(){
    
  if   ($(".hidden_2").is(":visible"))
           { $(".hidden_2").slideUp("slow", function(){
                      $(".togglehidden_2").removeClass("hide").addClass("show");
                        hidden_all();})}
                
  else   { $(".hidden_2").slideDown("slow", function(){
            $(".togglehidden_2").removeClass("show").addClass("hide");
                        hidden_all();})}
});

    $(".togglehidden_3").click(function(){
    
     if   ($(".hidden_3").is(":visible"))
           { $(".hidden_3").slideUp("slow", function(){
                      $(".togglehidden_3").removeClass("hide").addClass("show");
                        hidden_all();})}
                
  else   { $(".hidden_3").slideDown("slow", function(){
            $(".togglehidden_3").removeClass("show").addClass("hide");
                        hidden_all();})}
});

 });

</script>

<style>
.show {
 color: white;
    background-color: green;
}
.hide {
 color: white;
    background-color: red;
}
.starthidden {
 display: none;
}
</style>

</head>
<body>

<table>
<tbody>
<tr>
<td class="togglehidden_all show">+/-</td>
</tr>
<tr>
<td class="togglehidden_1 show">1</td>
</tr>
<tr>
<td class="hidden_1 starthidden">2</td>
</tr>
<tr>
<td class="togglehidden_2 show">3</td>
</tr>
<tr>
<td class="hidden_2 starthidden">4</td>
</tr>
<tr>
<td class="togglehidden_3 show">5</td>
</tr>
<tr>
<td class="hidden_3 starthidden">6</td>
</tr>
</tbody>
</table>

</body>
</html>
Sach
  • 75
  • 1
  • 10
0

I see you have modified your structure and can/are not opposed to changes to the markup. With that in mind, I set some classes and use them to simplify the code. I also allowed for initial "state" with classes on the toggle buttons of "show", "hide".

You can add a new "group" of toggles just by adding a new row pair, no special "class" so no need to modify code.

A fiddle to see it in action: https://jsfiddle.net/MarkSchultheiss/ud99cf0u/5/

Revised markup:

<table>
  <tbody>
    <tr>
      <td class="togglehidden_all">+/-</td>
    </tr>
    <tr>
      <td class="show  toggle-hide">1</td>
    </tr>
    <tr>
      <td class="hideme">2</td>
    </tr>
    <tr>
      <td class="toggle-hide">3</td>
    </tr>
    <tr>
      <td class="hideme">4</td>
    </tr>
    <tr>
      <td class="show toggle-hide">5</td>
    </tr>
    <tr>
      <td class="hideme">6</td>
    </tr>
  </tbody>
</table>

Revised code, note it has some initial "state" setting to allow for any markup/visibility and let that drive that initial visibility and class state. That is a good bit of this code. The last two do all the "active" work/event handling.

$(document).ready(function() {
  // simple extenders to use
  jQuery.fn.areAll = function(arg) {
    return this.filter(arg).length === this.length;
  };
  jQuery.fn.slideToggleBool = function(bool, options) {
    return (bool ? $(this).slideDown(options) : $(this).slideUp(options));
  };
  // cache these for use
  var allthem = $('.hideme');
  var allToggles = $('.toggle-hide');
  // set initial state of toggles and associated element, respects classes present
  allToggles.each(function() {
    var isShow = $(this).hasClass("show");
    if (isShow) {
      $(this).parents('tr').next().find('td.hideme').hide();
    } else {
      $(this).toggleClass("hide", !isShow);
    }
  });
  // used to set the "all" +/- button state
  function hidden_all() {
    var areVis = allthem.areAll(':visible');
    var allHidden = allToggles.filter(":hidden").length == allToggles.length;
    $(".togglehidden_all")
      .toggleClass("show", !allHidden)
      .toggleClass("hide", areVis && !allHidden);
    return !areVis;
  }

  // set initial "+/-" button color
  hidden_all();

  // these two do all the work
  $(".togglehidden_all").on('click', function() {
    var vis = hidden_all();
    $(this).toggleClass("show", !vis).toggleClass("hide", vis);
    allthem.slideToggleBool(vis, "slow");
    allToggles
      .toggleClass("show", !vis)
      .toggleClass("hide", vis);
  });
  $(".toggle-hide").on('click', function() {
    var myTarget = $(this).parents('tr').next().find('td.hideme');
    var isVis = myTarget.is(":visible");
    myTarget.slideToggleBool(!isVis, "slow");
    $(this).toggleClass("show", isVis).toggleClass("hide", !isVis);
  });
});
Mark Schultheiss
  • 32,614
  • 12
  • 69
  • 100