skip to Main Content

I am making an instant search function using .filter() and .toggle().

It is basically working, but I would like to make the "search result" better by hiding the whole parent .char-section div section when there is no result inside (ie. no .item in the below example).

For example, when searching for banana, the script currently works like this:
https://i.stack.imgur.com/UMrbK.png

The desired result should look like this :
enter image description here

Here is the script:

$(document).ready(function () {
  $("#myInput").on("keyup", function () {
    var value = $(this).val().toLowerCase();
    $(".item").filter(function () {
      $(this).toggle(
        $(":is(.title)", this)
          .text()
          .toLowerCase()
          .includes(value.toLowerCase())
      );
    });
  });
});
body {
  margin: 30px;
}
form {
  margin-bottom: 10px;
}
.title {
  display: block;
  margin-top: 0px;
  margin-bottom: 0px;
  padding-top: 0px;
  padding-bottom: 10px;
  font-size: 17px;
  line-height: 1.25em;
  font-weight: 700;
}
.char {
  position: absolute;
  left: 0%;
  top: 0%;
  right: auto;
  bottom: auto;
  z-index: 3;
  display: inline-block;
  margin-top: 20px;
  margin-bottom: 0px;
  margin-left: 2px;
  padding-top: 0px;
  padding-bottom: 0px;
  color: #036;
  font-size: 26px;
  line-height: 1em;
}
.item {
  position: relative;
  top: -20px;
  width: 100%;
  margin-top: 0px;
  margin-bottom: 10px;
  padding-top: 8px;
  padding-bottom: 8px;
}
.list {
  position: relative;
  left: 0%;
  top: 0%;
  right: 0%;
  bottom: auto;
  width: 100%;
  margin-top: 0px;
  margin-bottom: 0px;
  padding: 2px 0px 2px 80px;
}
.char-section {
  position: relative;
  width: 100%;
  height: auto;
  margin-top: 0px;
  margin-bottom: 0px;
  padding: 30px 0px;
  border-bottom: 3px solid #ddd;
}
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>

<form>
<input type="search" placeholder="Quick Search" class="h-filter-search" id="myInput">
<input type="reset" id="reset-btn" value="Reset">
</form>

<div class="ab-wrapper">
  <div id="A" class="char-section">
    <h5 class="char">A</h5>
    <div class="list">
      <div class="item">
        <p class="title">Apple</p>
      </div>
      <div class="item">
        <p class="title">Apple Juice</p>
      </div>
      <div class="item">
        <p class="title">Avocado</p>
      </div>
    </div>
  </div>
  <div id="B" class="char-section">
    <h3 class="char">B</h3>
    <div class="list">
      <div class="item">
        <p class="title">Banana</p>
      </div>
      <div class="item">
        <p class="title">Boiled Eggs</p>
      </div>
      <div class="item">
        <p class="title">Bamboo Juice</p>
      </div>
    </div>
  </div>
  <div id="C" class="char-section">
    <h3 class="char">C</h3>
    <div class="list">
      <div class="item">
        <p class="title">Candy</p>
      </div>
    </div>
  </div>
  <div id="D" class="char-section">
    <h3 class="char">D</h3>
    <div class="list">
      <div class="item">
        <p class="title">Disco</p>
      </div>
      <div class="item">
        <p class="title">Decaffeinated Juice</p>
      </div>
    </div>
  </div>
  <div id="E" class="char-section">
    <h3 class="char">E</h3>
    <div class="list"></div>
  </div>
  <div id="F" class="char-section">
    <h3 class="char">F</h3>
    <div class="list">
      <div class="item">
        <p class="title">Decaffeinated Juice</p>
      </div>
    </div>
  </div>
</div>

On CodePen: https://codepen.io/pen/qBYbdYx
☝️ Edit: updated with the script in answer

Big thanks for any idea!


PS. Another small problem is that reset button can only reset the input field, but not reset the whole results list. The user must focus the input and hit "Esc" key. I will put this as another question later.

2

Answers


  1. This can be done rather easily. If we look at your html structure, we realize that the main ‘container’ <div> for an item, is of class char-section. So if we’re searching through your title DIVs, we can get a reference to it’s parent using:

    .closest(".char-section")
    

    on the object in question.

    Now all we have to do is hide or show the whole container using the equally named show()/hide() methods in case the search was successful or not.

    Here’s an example:

    $(document).ready(function() {
      $("#myInput").on("keyup", function() {
        var value = $(this).val().toLowerCase();
        $(".item").filter(function(e) {
          let hit = $(":is(.title)", this).text().toLowerCase().includes(value.toLowerCase());
          $(this).toggle(hit);
          if (hit) {
            $(this).closest(".char-section").show();
          } else {
            $(this).closest(".char-section").hide();
          }
        });
      });
    });
    body {
      margin: 30px;
    }
    
    form {
      margin-bottom: 10px;
    }
    
    .title {
      display: block;
      margin-top: 0px;
      margin-bottom: 0px;
      padding-top: 0px;
      padding-bottom: 10px;
      font-size: 17px;
      line-height: 1.25em;
      font-weight: 700;
    }
    
    .char {
      position: absolute;
      left: 0%;
      top: 0%;
      right: auto;
      bottom: auto;
      z-index: 3;
      display: inline-block;
      margin-top: 20px;
      margin-bottom: 0px;
      margin-left: 2px;
      padding-top: 0px;
      padding-bottom: 0px;
      color: #036;
      font-size: 26px;
      line-height: 1em;
    }
    
    .item {
      position: relative;
      top: -20px;
      width: 100%;
      margin-top: 0px;
      margin-bottom: 10px;
      padding-top: 8px;
      padding-bottom: 8px;
    }
    
    .list {
      position: relative;
      left: 0%;
      top: 0%;
      right: 0%;
      bottom: auto;
      width: 100%;
      margin-top: 0px;
      margin-bottom: 0px;
      padding: 2px 0px 2px 80px;
    }
    
    .char-section {
      position: relative;
      width: 100%;
      height: auto;
      margin-top: 0px;
      margin-bottom: 0px;
      padding: 30px 0px;
      border-bottom: 3px solid #ddd;
    }
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js"></script>
    
    <form>
      <input type="search" placeholder="Quick Search" class="h-filter-search" id="myInput">
      <input type="reset" id="reset-btn" value="Reset">
    </form>
    
    <div class="ab-wrapper">
      <div id="A" class="char-section">
        <h5 class="char">A</h5>
        <div class="list">
          <div class="item">
            <p class="title">Apple</p>
          </div>
          <div class="item">
            <p class="title">Apple Juice</p>
          </div>
          <div class="item">
            <p class="title">Avocado</p>
          </div>
        </div>
      </div>
      <div id="B" class="char-section">
        <h3 class="char">B</h3>
        <div class="list">
          <div class="item">
            <p class="title">Banana</p>
          </div>
          <div class="item">
            <p class="title">Boiled Eggs</p>
          </div>
          <div class="item">
            <p class="title">Bamboo Juice</p>
          </div>
        </div>
      </div>
      <div id="C" class="char-section">
        <h3 class="char">C</h3>
        <div class="list">
          <div class="item">
            <p class="title">Candy</p>
          </div>
        </div>
      </div>
      <div id="D" class="char-section">
        <h3 class="char">D</h3>
        <div class="list">
          <div class="item">
            <p class="title">Disco</p>
          </div>
          <div class="item">
            <p class="title">Decaffeinated Juice</p>
          </div>
        </div>
      </div>
      <div id="E" class="char-section">
        <h3 class="char">E</h3>
        <div class="list"></div>
      </div>
      <div id="F" class="char-section">
        <h3 class="char">F</h3>
        <div class="list">
          <div class="item">
            <p class="title">Decaffeinated Juice</p>
          </div>
        </div>
      </div>
    </div>
    Login or Signup to reply.
  2. I have to disagree with another answer:

          if (hit) {
            $(this).closest(".char-section").show();
          } else {
            $(this).closest(".char-section").hide();
          }
    

    With this code, the "char-section" is going to be visible if and only if the last item of the section is. So the "A" section won’t be visible if the search is on "Apple", for example.

    My suggestion is 1/ hide all the "char-sections" 2/ show them in the same each/filter loop if one of their "item" children is visible, as follows:

    $(document).ready(function () {
    
      $("#myInput").on("keyup", function () {
        var value = $(this).val().toLowerCase();
    // hide all the sections
        $(".char-section").hide();
    // 'each' better than 'filter' here, because there's no filtering
        $(".item").each(function () {
            if ($("p.title", this).text().toLowerCase().includes(value))
    // shows the item AND its "char-section" parent
              $(this).show().parents(".char-section").show();
            else 
    // hides the item, leaves its parent alone
              $(this).hide();
          });
      });
    });
    

    HTH

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search