Show elements after specific Class

Viewed 67

With jQuery I want to hide all li elements and show only li with class .selected and others elements that have a minus (-) symbol.

This is the result I expect when I click on the button:

<ul>
  <li class="selected">Item 5</li>
  <li>- Item 6</li>
  <li>- Item 7</li>
  <li>- Item 8</li>
</ul>

<input type="button" id="btm" value="show" />

var $j = jQuery.noConflict();
$j(document).ready(function() {
  $j("input#btm").bind("click", function() {
    for (var i = 1; i <= 12; i++) {
      if ($j('.chzn-results li:nth-child(' + i + ')').hasClass("selected") || $j('.chzn-results li:nth-child(' + i + ')').text().indexOf('- ') >= 0) {
        $j('.chzn-results li:nth-child(' + i + ')').show();
      }
    }
  });
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="chzn-results">
  <li>Item 1</li>
  <li>- Item 2</li>
  <li>- Item 3</li>
  <li>- Item 4</li>
  <li class="selected">Item 5</li>
  <li>- Item 6</li>
  <li>- Item 7</li>
  <li>- Item 8</li>
  <li>Item 9</li>
  <li>Item 10</li>
  <li>Item 11</li>
  <li>- Item 12</li>
</ul>

<input type="button" id="btm" value="show" />

3 Answers

You can use a combination of .index() and .slice() to select items up to the selected one.

To find the first non-dash entry would be much easier if you could add some classes, but looks like you're using chosen so possibly can't change the html.

Keeping it to a simple for loop with break when a match is no longer found gives:

var li = $("ul.chzn-results>li");
var pos = li.filter(".selected").index();
var endpos = pos+1;
for (var i = endpos; i<li.length; ++i)
{
    //console.log(li.eq(i).text().substr(0, 1))
    if (li.eq(i).text().substr(0, 1) != "-")
        break;
    endpos = i;
}

li.slice(0, pos).hide();
li.slice(endpos+1).hide();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="chzn-results">
  <li>Item 1</li>
  <li>- Item 2</li>
  <li>- Item 3</li>
  <li>- Item 4</li>
  <li class="selected">Item 5</li>
  <li>- Item 6</li>
  <li>- Item 7</li>
  <li>- Item 8</li>
  <li>Item 9</li>
  <li>Item 10</li>
  <li>Item 11</li>
  <li>- Item 12</li>
</ul>

<input type="button" id="btm" value="show" />


Bit cleaner without the for loop

var li = $("ul.chzn-results>li");
var pos = li.filter(".selected").index();
// can all be on one line, separated for readability
var endpos = li.filter(".selected")
               .nextAll()
               .filter((i,e) => $(e).text().substr(0,1) != "-")
               .first()
               .index() - 1;
li.slice(0, pos).hide();
li.slice(endpos+1).hide();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="chzn-results">
  <li>Item 1</li>
  <li>- Item 2</li>
  <li>- Item 3</li>
  <li>- Item 4</li>
  <li class="selected">Item 5</li>
  <li>- Item 6</li>
  <li>- Item 7</li>
  <li>- Item 8</li>
  <li>Item 9</li>
  <li>Item 10</li>
  <li>Item 11</li>
  <li>- Item 12</li>
</ul>

<input type="button" id="btm" value="show" />


For the comment, if a "child" item is selected, get the "parent" first

var li = $("ul.chzn-results>li");
var pos = li.filter(".selected")
            .prevAll()
            .filter((i,e) => $(e).text().substr(0,1) != "-")
            .first()
            .index();
// can all be on one line, separated for readability
var endpos = li.filter(".selected")
               .nextAll()
               .filter((i,e) => $(e).text().substr(0,1) != "-")
               .first()
               .index() - 1;
li.slice(0, pos).hide();
li.slice(endpos+1).hide();
.selected { color: red; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="chzn-results">
  <li>Item 1</li>
  <li>- Item 2</li>
  <li>- Item 3</li>
  <li>- Item 4</li>
  <li>Item 5</li>
  <li class="selected">- Item 6</li>
  <li>- Item 7</li>
  <li>- Item 8</li>
  <li>Item 9</li>
  <li>Item 10</li>
  <li>Item 11</li>
  <li>- Item 12</li>
</ul>

<input type="button" id="btm" value="show" />

You can use .addBack() and .nextAll() to traverse through all li after selected class and then use each loop and compare each li if condition statisfy show that li.

Demo Code :

$("input#btm").bind("click", function() {
  $(".chzn-results li").hide() //hide all
  $(".chzn-results li.selected").nextAll().addBack().each(function() {
    //check condtion
    if ($(this).hasClass("selected") || $(this).text().indexOf("-") > -1) {
      $(this).show() //show ..
    } else {
      return false; //break loop :P 
    }
  })
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<ul class="chzn-results">
  <li>Item 1</li>
  <li>- Item 2</li>
  <li>- Item 3</li>
  <li>- Item 4</li>
  <li class="selected">Item 5</li>
  <li>- Item 6</li>
  <li>- Item 7</li>
  <li>- Item 8</li>
  <li>Item 9</li>
  <li>Item 10</li>
  <li>Item 11</li>
  <li>- Item 12</li>
</ul>

<input type="button" id="btm" value="show" />

In this solution, I used the double exclusion of the selectors required for display using the not() method, which specifies the tag li with the class selected, and all subsequent tags li containing the character (-) defining the :contains() selector.

$("#btn").on("click", function () {
    $(".chzn-results >").not($("li.selected")).not($("li.selected ~ :contains(-)")).hide();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul class="chzn-results">
    <li>Item 1</li>
    <li>- Item 2</li>
    <li>- Item 3</li>
    <li>- Item 4</li>
    <li class="selected">Item 5</li>
    <li>- Item 6</li>
    <li>- Item 7</li>
    <li>- Item 8</li>
    <li>Item 9</li>
    <li>Item 10</li>
    <li>Item 11</li>
    <li>- Item 12</li>
</ul>

<input type="button" id="btn" value="show" />

Related