views:

45

answers:

2

Hi everyone!

I'm learning jQuery right now and the first "bigger" project is a self made Accordion/sliding Navigation.

My HTML Code looks like this:

<dl>
 <dt><a href="#">Prologue</a></dt>
<dd id="prolog">
 <div>TEST</div>
</dd>

<dt><a href="#">Projekte</a></dt>
<dd id="projekte">
 <ul>
     <li>TEST</li>
        <li>TEST</li>
        <li>TEST</li>
        <li>TEST</li>
</ul>
</dd>

<dt><a href="#">Fotografie</a></dt>
<dd id="fotos">
 <ul>
     <li>TEST</li>
        <li>TEST</li>
        <li>TEST</li>
        <li>TEST</li>
</ul>
</dd>

<dt><a href="#">Analog</a></dt>
<dd id="analog">
 <ul>
     <li>TEST</li>
        <li>TEST</li>
        <li>TEST</li>
        <li>TEST</li>
</ul>
</dd>

<dt><a href="#">Über mich</a></dt>
<dd id="about">
 <ul>
     <li>TEST</li>
        <li>TEST</li>
        <li>TEST</li>
        <li>TEST</li>
</ul>
</dd>

<dt><a href="#">Kontakt</a></dt>
<dd id="kontakt">
 <ul>
     <li>TEST</li>
        <li>TEST</li>
        <li>TEST</li>
        <li>TEST</li>
</ul>
</dd>

And here comes the jQuery code. The idea is to check if the user clicks on an open accordion item and if he does, just close it. Otherwise (when the clicked item is closed) it checks, if any other of the accordion items is open. If they are all hidden, it opens the clicked item. Otherwise it closes all items (don't know how to get only the open one) and opens the clicked item. This is what it looks like:

$("dt a").click(function(){

var checkElement = $(this).parent("dt").next("dd");

var main1 = $('#prolog'); var main2 = $('#projekte'); var main3 = $('#fotos'); var main4 = $('#analog'); var main5 = $('#about'); var main6 = $('#kontakt');

if(checkElement.is(':visible')) {
    $(this).parent("dt").next("dd").slideUp("normal"); 
    return false
} else {
    if( (main1.is(':hidden')) &&
        (main2.is(':hidden')) &&    
        (main3.is(':hidden')) &&
        (main4.is(':hidden')) &&
        (main5.is(':hidden')) &&
        (main6.is(':hidden')) ) {$(this).parent("dt").next("dd").slideDown("normal");}
    else {
        $("dd").slideUp("normal"), checkElement.slideDown("normal");
    }

    return false;
};

});

So far it works fine (though the second if-request with the bunch of variables doesn't look very professional, if you could help me out here, it would be nice, although it's not the main issue). Next goal is to put the closing and opening of the accordion items in a row. I want the slideUp first and after it's finished, the slideDown should start. So I changed

else {
        $("dd").slideUp("normal"), checkElement.slideDown("normal");
    }

to

else {
   $("dd").slideUp("normal", function() { checkElement.slideDown('normal') });
}

But here comes the bug: It first closes + opens at the same time and after that, it does the same but in a row (like I want it to). Seems like it does this part of the function twice, but one time simultaneous and afterward in a row. I just can't figure out, where the first, simultaneous animation comes from. Especially because if the functions aren't in a row, it works just fine (without doing the same twice).

Would be nice, if anyone could help me with this.

Regards
Lucas

PS: And please don't send me over to a finished Accordion (plugin), I want to learn and understand creating one!

PS2: Sorry for my poor English, I'm from Germany. ;-)

PS3: I leave for holidays later on, but I'll be back in 10 days!

A: 

When you call this:

 $("dd").slideUp()

You're calling it for all <dd> elements, and some are already hidden, finishing immediately and running the callback immediately, so instead just animate the visible ones, like this:

$("dd:visible").slideUp("normal", function() {
  checkElement.slideDown("normal");
});

This fixes the immediate problem (test here). Here's an overall more compact version though:

$("dt a").click(function(){
    var dd = $(this).parent("dt").next("dd");
    if(!$("dd:visible").slideUp(function() { dd.slideDown(); }).length)
      dd.slideDown();    
    return false;
});​

You can give it a try here.

Nick Craver
@Nick could you comment the line: if(!$("#menu dd:visible").slideUp(function() { dd.slideDown(); }).length) so it may help my understanding. I know it's not my question but to learn more about jQuery it would help to understand what is going on.
RyanP13
@RyanP13 - Then `.length` is how many elements were at the end of that chain, if it's 0 (`false` in JavaScript) that means none were slide up showing this one later (all are collapsed), so we're saying if there are 0 sliding up, we need to go ahead and slide this one down, that make sense?
Nick Craver
@Nick. Yes i thought it was seomthing like that. Appreciate the comments and it really helps in learning how to approach and think about code differently.
RyanP13
A: 

How do I add a class the the slide functions.I have a class named "active". So how do I add or remove this class during the slideup or down. I tried to you toggleclass but didn't work

Parker