user244394
user244394

Reputation: 13448

Jquery toggle issue not closing everything or opening

I have the following code which toggles fine. I can toggle individually and toggle all together at the same time.

the problem arises when i have one of the individual items open, so when i select toggle all. it closes the opened ones and opens the closed one.. which i dont want to happen.

I want all opened items to close and also keep the existing closed items close and same for open, open all item and also keep any exiting items open.

Here is my fiddle demo and code below:

DEMO

Javascript

function toggle()   {
    $("#showhide").click(function(){
        $("#lorem1").toggle(1000,function(){
            $("#231-minus").toggle();
             $("#231-plus").toggle();
        });

         $("#lorem2").toggle(1000,function(){
            $("#500-minus").toggle();
             $("#500-plus").toggle();
        });
         $("#lorem3").toggle(1000,function(){
            $("#850-minus").toggle();
             $("#850-plus").toggle();
        });
    });


}


$(document).ready(function(){
    toggle();



      $("h3.viol-header1").click(function(){
       $("#lorem1").toggle(1000,function(){
             $("#231-minus").toggle();
             $("#231-plus").toggle();
        });
      });

          $("h3.viol-header2").click(function(){
       $("#lorem2").toggle(1000,function(){
            $("#500-minus").toggle();
             $("#500-plus").toggle();
        });
      });

              $("h3.viol-header3").click(function(){
       $("#lorem3").toggle(1000,function(){
            $("#850-minus").toggle();
             $("#850-plus").toggle();
        });
      });

});

Upvotes: 0

Views: 357

Answers (1)

Roko C. Buljan
Roko C. Buljan

Reputation: 206102

jsBin demo

There's so many odd things in your code, I can only hope to cover them all. Let's start.

  • HTML align attribute is deprecated. Use CSS instead (text-align property)
  • Don't use styling classes like h3.viol-he... inside a JS logic. One day that h3 could change to h4 inside HTML, and you'll find yourself asking why jQuery suddenly broke.
    You got the idea. Create instead classes like jQ-accordion-trigger or something more descriptive and unbreakable.
  • Repeatitive classes and code like h3.viol-header1, h3.viol-header2 etc... that actually perform a similar task should be avoided. Like I said earlier, use a single specific class, don't rely in ID unless you're completely sure that you need them for your JS code.
  • Don't use inline styles style="blah blah". Use your stylesheet for styling,
    unless you like unreadable HTML.

One principle I'll show you (might not be the best cause I'm using the jQuery's .next() selector) is to make your Triggers and the slideable DIVs as sibling elements:

  <h3 class="toggleNext">Lorem 1</h4>
  <div>111....</div>

  <h3 class="toggleNext">Lorem 2</h4>
  <div>222....</div>

  <h3 class="toggleNext">Lorem 3</h4>
  <div>333...</div>

See how nice the HTML looks now?

How are that DIV elements hidden by default?
Using the Adjacent Sibling selector +:

.toggleNext + * { /* hides adjacent sibling element */
  display: none;          
}

Where are the buttons gone?
Create them using CSS's :after pseudo:

.toggleNext:after{        /* THE +/- SYMBOLS */
  font-family: Helvetica, Arial, sans-serif;
  letter-spacing: 1px;
  border-radius:  50%;  
  line-height:    19px;
  font-weight: 400;
  text-align:  center;
  transition:  background .4s;
  height:  20px;
  width:   20px;
  float:   right;
  color:   #fff;  

  background:  #369335;    /* Green (Default) */
  content:     "+";
}
.toggleNext.opened:after{ /* Class toggled by jQuery */
  background: #A83C3D;    /* Red */
  content:    "-";
}

What about my Show/Hide All button?
Don't use ID, probably one day you'll want to have two or more such buttons (see demo). Use class:

<p class="text-right">
  <a href="#" class="toggleAll">Show/Hide All </a>
</p>

See? I've removed the unnecessary ID and added a class you can use everywhere in your document:

/* ::: HELPER CLASSES */
.text-right { text-align: right; }

jQuery (see how fun now is to play with JS logic)

var $togglers = $(".toggleNext"); // Cache your toggler elements

// ::: SLIDE-TOGGLE BUTTONS (...all it takes)
$togglers.click(function( event ){
  // event.preventDefault(); // prevent page jumps (if you'll use `a` elements one day)
  $(this).toggleClass("opened").next().slideToggle();
});

// ::: TOGGLE ALL BUTTONS
// (now it's a class, so you can have more than one)
// This buttons are a bit specific in logic, think about it,
// If user opened all items, would make sense to OPEN-ALL 
// after a first click? NO.
$('.toggleAll').click(function( event ){
  event.preventDefault(); // prevent page jumps
  // The below variable will return `true` if
  // at least one $trigger element has a class "opened"
  var isOneOpened = $togglers.hasClass("opened");
  if(isOneOpened){        // If one was opened: CLOSE ALL
    $(".opened").click(); // Perform a click (only .opened togglers)
  }else{
    $togglers.click();    // All are closed: OPEN ALL
  }
});

Now you can click even directly in the +/- symbol cause it's part of the trigger element (h3 in your specific case)

Principle2
If you don't want to use sibling triggers and slidables, than you can use data-* attribute to target a specific element distant in the DOM tree.

Upvotes: 2

Related Questions