Question

I have a 'tree' of information that's displayed in many nested lists (ul li ul li ....). Two problems:

  1. When I click a <li>, the parent ul is toggled as well as the child.
  2. If I click on an <li> in a nested list that does not have a ul in it (say, Blue under Cranberry below) the parent ul is toggle, even though this shouldn't be matching 'li.has(ul)'.

I've tried various JQuery selectors, next(ul), children().first(), etc with the same results. No luck - though I'm sure I'm just missing something simple here.

On JSFiddle.

$('li.has(ul)').click(function() {
    $(this).children('ul').toggle();
});

And the html:

<ul class="unstyled" id="full_ontology">
    <li>Apple</li>
    <li>Banana</li>
    <li>Cranberry
        <ul>
            <li>Blue</li>
            <li>Red
                <ul>
                    <li>Round</li>
                    <li>Square</li>
                    <li>Circular</li>
                </ul>
            </li>
            <li>Purple</li>
        </ul>
    </li>
    <li>Date</li>
    <li>Elderberry
        <ul>
            <li>Yellow</li>
            <li>Pink</li>
            <li>Black</li>
        </ul>
    </li>
    <li>Fig</li>
</ul>
Était-ce utile?

La solution

The problem is event propagation, prevent it

$('li:has(ul)').click(function (e) {
    $(this).children('ul').addClass('thisOne').toggle();
});
$('li').click(function (e) {
    e.stopPropagation();
});

Demo: Fiddle

Autres conseils

It's all about propagation.

Here is the working JavaScript:

$('li').click(function(e) {
    if ($(this).has('ul')) {
        $(this).children('ul').addClass('thisOne').toggle();
    }

    e.stopPropagation();
});

JSFiddle: http://jsfiddle.net/zkFGU/3/

Basically, first you want this event on all of the list items, not just the ones that have the ul. The reason is because if you don't, you can't stop propagation. For example, "Blue" under "Cranberry" has no list, so it wouldn't call the event. However, because "Blue" is actually in Cranberry, which is a list item and does trigger the event, clicking Blue counts as clicking Cranberry, so Cranberry retracts. By giving Blue a change to chance to stop propagation, it prevents Cranberry from erroneously collapsing.

The other part of stopping propagation is simply to stop parents. We want only the element we directly clicked on (which is triggered first) and no other element to (attempt) to toggle.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top