1

I got the following structure: - nested UL

<ul class="depth-one">
    <li>Category 1
        <ul class="depth-two">
            <li > Category 1.1</li>
            <li> Category 1.2</li>
            <li> Category 1.3</li>
        </ul>
    </li>
    <li> Category 2
        <ul class="depth-two">
            <li>Category 2.1</li>
            <li>Category 2.2</li>
            <li>Category 2.3</li>
        </ul>
    </li>
    <li>Category 3
        <ul class="depth-two">
            <li>Category 3.1</li>
            <li>Category 3.2</li>
            <li>Category 3.3</li>
        </ul>
    </li>
</ul>

I've applied a rule with CSS:

ul{
    list-style: none;
    padding:0;
    margin:0;
}
.depth-one{
    display:block;
}
.depth-two{
    display:none;
}

which leaves only the MAIN category shown.

$(document).ready(function() {
    $(".depth-one > li").click(function() {
        selector = $(this).find(' > .depth-two');
        if($(selector).css("display") == "none"){
            selector.slideDown(800);
        } else {
            selector.slideUp(800);
        }
    });
});

this one, toggles the SUB categories when the MAIN category is being clicked.

here is a fiddle to demonstrate: http://jsfiddle.net/NB4bN/1/

Now, as you can see, when I'm clicking on the SUBCATEGORY, the whole category slides up, any idea why?

I'm trying to achieve that only when I click on the MAIN category, the subcategory will slides up, otherwise, nothing happens when I click on the sub <li> items.

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
kfirba
  • 5,231
  • 14
  • 41
  • 70

2 Answers2

5

Here is a fix for your problem: http://jsfiddle.net/smerny/NB4bN/2/

$(document).ready(function () {
    $(".depth-one > li").click(function (e) {
        if (e.currentTarget == e.target) {
            selector = $(this).find(' > .depth-two');
            if ($(selector).css("display") == "none") {
                selector.slideDown(800);
            } else {
                selector.slideUp(800);
            }
        }
    });
});

I added the check to see if currentTarget and target were the same. So you know if the click is on an element within your li or the li itself.

Smern
  • 18,746
  • 21
  • 72
  • 90
  • Works perfectly! Thanks alot! If possible, I would like to ask you to explain me a little bit about this e.currentTarget and e.target, didn't really understand the different or their usage. – kfirba Aug 06 '13 at 19:47
  • @kfirba Here are a couple log statements that will show the difference between the two: http://jsfiddle.net/smerny/NB4bN/4/ - you'll notice if you click on a sub-li, the target will be the sub-li while the currentTarget will always be the li that matches your selector for the bind. – Smern Aug 06 '13 at 19:50
  • I don't see any difference between the 2 calls, they both produce the same output for me(console) – kfirba Aug 06 '13 at 19:57
  • If you click on a sub-li, you'll get something like this for the currentTarget: `Category
    • Category 1.1
    • Category 1.2
    • Category 1.3
    ` and something like this for the target: `Category 1.1 ` showing basically that the currentTarget is the li that matched your bind while the target is the element that you clicked on.
    – Smern Aug 06 '13 at 20:03
  • I see! thanks alot! If you don't mind, can you look at this fiddle:http://jsfiddle.net/NB4bN/5/ What I was trying to do is, that if there is any SUB CATEGORY which is already shown, and the user chooses to open another one, it will first close the OPEN sub category and then show the sub category that the user has chosen – kfirba Aug 06 '13 at 20:09
  • @kfirba, you can do a selector.not(this) where the selector is `.depth-one > li` and close them up if you are opening `this`... I'm in a hurry to do something now or I'd write something up quick but you should really ask a separate question for that anyway. – Smern Aug 06 '13 at 20:15
4

An easy fix is to stop the event bubbling by adding:

$('li li').click(function (e) {
    e.stopPropagation();
});

jsFiddle example

.stoppropagation() prevents an event from bubbling up the DOM tree. So what the above chunk does is look for any list items that are children of other list items and whenever it registers a click on one, it stops the click event from bubbling up the DOM.

j08691
  • 204,283
  • 31
  • 260
  • 272
  • Hey! thanks for your solution! I would like to ask you to exlain me your solution, I don't like using code which I don't understand what it does :) Could you explain me that this stopPropagation() function does, and why you select `li li` as your selector? Thanks! – kfirba Aug 06 '13 at 19:48
  • Sure, answer updated. Let me know if you still have questions. – j08691 Aug 06 '13 at 19:52
  • "prevents an event from bubbling up the DOM tree." what does that mean >_ – kfirba Aug 06 '13 at 19:58
  • See http://stackoverflow.com/questions/4616694/what-is-event-bubbling-and-capturing and http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html for an explanation about the DOM, events, bubbling, and propagation. – j08691 Aug 06 '13 at 20:05
  • A very good link to describe it! many thanks! just one thing, if you are stopping the bubbling, it means that NONE of the click event will occure, right? – kfirba Aug 06 '13 at 20:14
  • No, you're not stopping the click event, you're just preventing the click event from propagating to the parent elements, so they are essentially unaware of it. – j08691 Aug 06 '13 at 20:23