1

This is a build off of my previous question: Select a child of a child

I now have a <ul> within another <ul>. The behavior is an expandable menu. I'm doing this by adding and removing classes. For some reason...on the sub list - it completely removes the <li> elements from the DOM rather than just toggling it's classes. Why would it do that!?

You can see an example below:

$(function() {
  // main expansion element
  $(".expander").click(function() {
    var subShown = $("ul > li", this).hasClass("show");
    if (!subShown) {
      $(".indented", this).slideDown('100').addClass("show");
      $(".caret", this).addClass("reversedCaret");
    } else {
      $(".indented", this).slideUp('100').removeClass("show");
      $(".caret", this).removeClass("reversedCaret");
    }
  });

  // sub expansion element
  $(".sub-expander, .caret").click(function() {
    var subSelectText = $(".sub-expander").text();
    if (subSelectText != "More") {
      $(".indented--sub", this).slideUp('100').removeClass("show");
      $(".caret", this).removeClass("reversedCaret");
      $(".more-or-less").text("More");
    } else {
      $(".indented--sub", this).slideDown('100').addClass("show");
      $(".caret", this).removeClass("reversedCaret");
      $(".more-or-less").text("Show Less");
    }
  });

  // stop propagation on the link element within .expander class
  $(".indented").click(function(event) {
    event.stopPropagation();
  });
});
.expander:hover {
  cursor: pointer;
}

.sub-expander--indented {
  padding: 0 0 0 23px;
}

.sub-caret {
  margin-right: 75px;
}

.indented,
.indented--sub {
  display: none;
}

.show {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

<div class="expander">
  <span class="caret downCaret right visibleCaret">+</span>
  <ul>
    <li class="category">Item 1
      <a href="http://www.google.com"></a>
    </li>
    <li class="indented"><a href="http://www.google.com">Item 2</a></li>
    <li class="indented"><a href="http://www.google.com">Item 3</a>

    <ul class="sub-expander indented more" style="padding-top: 
0px;">
      <li class="indented--sub"><a href="http://www.google.com" class="moreLiAs">Chapter 5</a></li>
      <li class="indented--sub"><a href="http://www.google.com" class="moreLiAs">Chapter 6</a></li>
      <li class="indented--sub"><a href="http://www.google.com" class="moreLiAs">Chapter 7</a></li>
      <span class="sub-caret moreCaret visibleLessCaret right">+</span>
      <li class="more-or-less less sub-expander--
indented">More</li>
    </ul>
    </li>
  </ul>
</div>

I'm giving it a separate classname to differentiate from the main section so that they don't show on initial open, so I'm not sure why it is behaving the way it is. It seems like there is a better way to go about this but I don't know what that would be.

UPDATE: was pointed out I did not have valid HTML. Fixed it following this thread. Still broken.

UPDATE #2: It seems like the problem is .text() - so it completely erases everything? I thought it just replaced the text node, and not all of it's children. I tried .html() but it does the same thing. What method do I use to just replace text then?

UPDATE #3 - one answer suggests I needed a more specific selector. I gave the list item a class of .more-or-less but doing that, it doesn't expand at all.

kawnah
  • 3,204
  • 8
  • 53
  • 103
  • 2
    You have invalid HTML, UL are not supposed to be direct children of other UL's. The only valid child of a UL is a LI. Also your removeClass call isnt removing your content, it is your `$(".sub-expander").text()` calls – Patrick Evans Nov 13 '17 at 17:59
  • Why not? This suggests otherwise: https://stackoverflow.com/questions/5899337/proper-way-to-make-html-nested-list – kawnah Nov 13 '17 at 18:04
  • Wait it needs to in an li ok – kawnah Nov 13 '17 at 18:05
  • You are deleting items by using the `text()` method: it replaces any child elements and content by the text you provide. – trincot Nov 13 '17 at 18:17
  • What would be a viable alternative for what I'm trying to do here? so far I've tried `.html()` , `.replace()` and `.replaceWith()` – kawnah Nov 13 '17 at 18:18
  • I didn't know that's how `.text()` worked - that's super misleading because I was under the assumption it replaces the inner text of the targeted element, not all of it's children. – kawnah Nov 13 '17 at 18:21
  • It is not clear to me what you want the display to be after each click. Maybe you could add images on what the display should look like after specific clicks. I'm quite sure you are overcomplicating things. – trincot Nov 13 '17 at 19:41

1 Answers1

0

You'd probably want to use a more strict selector.

In your example case you use .sub-expander to select the node of which you want to replace the text. This matches with the ul.sub-expander however.

Since you want it to replace the text of the li.sub-expander the simplest thing you could do would be to use a more specific selector: $("li.sub-expander").text("Show Less"); or (better) give the node which contains the text you want to replace another classname, id or other identifier to prevent targeting a different element.