skip to Main Content

I have a dynamically generated navigation structure shown. Each location has storetypes generated from the stores at the location.

I need to remove duplicates per location so that groceries can appear in both locations. I tried the common jquery solution below which removes duplicates but it results in each storetype appearing only in one location.

var seen = {};
$("ul#storetypes").find("li").each(function(index, html_obj) {
  txt = $(this).text().toLowerCase();

  if (seen[txt]) {
    $(this).remove();
  } else {
    seen[txt] = true;
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="menu">
  <li>Location 1
    <ul id="storetypes" class="sub-menu">
      <li>groceries</li>
      <li>cakes</li>
      <li>motor spares</li>
      <li>groceries</li>
    </ul>
  </li>
  <li>Location 2
    <ul class="sub-menu">
      <li>groceries</li>
      <li>motor spares</li>
      <li>motor spares</li>
      <li>groceries</li>
    </ul>
  </li>
</ul>

3

Answers


  1. what you did is correct, but just do it for every <ul>.

    $("ul.storetypes").each(function() {
      var seen = {};
      $(this).find("li").each(function(index, html_obj) {
        txt = $(this).text().toLowerCase();
        if (seen[txt]) {
          $(this).remove();
        } else {
          seen[txt] = true;
        }
      });
    })
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <ul class="menu">
      <li>Location 1
        <ul class="sub-menu storetypes">
          <li>groceries</li>
          <li>cakes</li>
          <li>motor spares</li>
          <li>groceries</li>
        </ul>
      </li>
      <li>Location 2
        <ul class="sub-menu storetypes">
          <li>groceries</li>
          <li>motor spares</li>
          <li>motor spares</li>
          <li>groceries</li>
        </ul>
      </li>
    </ul>
    Login or Signup to reply.
  2. You just need to target your top-level iteration at each sub-list.

    Then iterate its children and remove duplicates.

    Also, you don’t need jQuery.

    document.querySelectorAll(".sub-menu").forEach((list) => {
      const seen = new Set();
      list.querySelectorAll(":scope > li").forEach((item) => {
        const text = item.textContent.trim();
        if (seen.has(text)) {
          item.remove();
        } else {
          seen.add(text);
        }
      });
    });
    <ul class="menu">
      <li>Location 1
        <ul id="storetypes" class="sub-menu">
          <li>groceries</li>
          <li>cakes</li>
          <li>motor spares</li>
          <li>groceries</li>
        </ul>
      </li>
      <li>Location 2
        <ul class="sub-menu">
          <li>groceries</li>
          <li>motor spares</li>
          <li>motor spares</li>
          <li>groceries</li>
        </ul>
      </li>
    </ul>
    Login or Signup to reply.
  3. You can do it like this:

    $("ul.sub-menu li").each(function(index, html_obj) {
      if ($(this).prevAll(":contains(" + $(this).text() + ")").length > 0) {
        $(this).remove();
      }
    });
    

    This will look into each .sub-menu and see if any ‘li’ exist already with the same text, and remove the duplicated.

    Demo

    $("ul.sub-menu li").each(function(index, html_obj) {
      if ($(this).prevAll(":contains(" + $(this).text() + ")").length > 0) {
        $(this).remove();
      }
    });
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
    <ul class="menu">
      <li>Location 1
        <ul id="storetypes" class="sub-menu">
          <li>groceries</li>
          <li>cakes</li>
          <li>motor spares</li>
          <li>groceries</li>
        </ul>
      </li>
      <li>Location 2
        <ul class="sub-menu">
          <li>groceries</li>
          <li>motor spares</li>
          <li>motor spares</li>
          <li>groceries</li>
        </ul>
      </li>
    </ul>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search