How can I filter my bootstrap 4 navbar links with a search bar? How can I filter my bootstrap 4 navbar links with a search bar? jquery jquery

How can I filter my bootstrap 4 navbar links with a search bar?


The approach I've used is to remember which items match, and then use that list to un-hide the parents.

Updated Fiddle: https://jsfiddle.net/j2gpann3/1/

The advantage of this approach is that the hidden sub-menu items (like 'BMW' etc.) will now show up in the search and won't have huge gaps above them from the other hidden items. The regex search searches for occurences of each word, so even if they are out of order to the menu item text, it will still match.

$('.search-filter').on('keyup', function() {  var matches = [];  var input = $.trim($('.search-filter').val());  var val = '^(?=.*\\b' + input.split(/\s+/).join('\\b)(?=.*\\b') + ').*$'; // using individual word matching filter from http://stackoverflow.com/a/9127872/1544886  var filter = RegExp(val, 'i');  if (input.length === 0) { // show all if filter is empty    $('.collapse').removeClass('show').addClass('collapsed'); // hide collapsable items fast.    $('.hide').removeClass('hide'); // remove any hidden elements from previous searches  } else {    $('.collapse').addClass('show'); // show all collapsed items    $('ul.sidebar-nav a:not(".home")').filter(function() { // skip home <li> so it shows permanently        $this = $(this);        // test for a match to search string        text = $this.text().replace(/\s+/g, ' ');        var isMatch = filter.test(text);                // store match so we can unhide parents of this item         if (isMatch) matches.push($this);        return !isMatch;    }).parent().addClass('hide'); // this hides any <li> that doesn't match search terms. Hiding <a> results in large gaps in the output    $.each(matches, function() { // unhide parents of our matches        this.parentsUntil(".sidebar-nav", ".hide").removeClass('hide');    });  }});

The demo requires a home class added to the Home link to prevent it from being hidden by the search:

<a class="nav-link home" href="#"><i class="fa fa-fw fa-home"></i> Home</a>

and a CSS class for hide added:

.hide {  display: none;}


Okay, I think i've figured it out on my own (with a little help from this post for a case insensitive filter).

1) I updated the links by wrapping them in a div with id #link-content, to separate my filter from the home and search input.

2) I added the case insensitive method referenced above

My HTML:

   <ul class="sidebar-nav navbar-nav">      <li class="nav-item active">         <a class="nav-link" href="#"><i class="fa fa-fw fa-home"></i> Home</a>      </li>      <li class="nav-item">         <label for="nav-search" class="col-2 col-form-label sr-only">Search links</label>         <div class="col p-2">            <input class="form-control form-control-sm search-filter" type="search" id="nav-search" placeholder="Search for tools">         </div>      </li> <div id="link-content"><!-- added this to wrap the links-->           <li class="nav-item">         <span class="navbar-brand">Popular tools</span>      </li>      <li class="nav-item filter">         <a class="nav-link" href="#"><i class="fa fa-fw fa-calculator"></i> Calculator</a>      </li>      <li class="nav-item  filter">         <a class="nav-link" href="#"><i class="fa fa-fw fa-battery-3"></i> Battery </a>      </li>      <li class="nav-item  filter">         <a class="nav-link" href="#"><i class="fa fa-fw fa-database"></i> Pancake Batter</a>      </li>      <li class="nav-item  filter">         <a class="nav-link" href="#"><i class="fa fa-fw fa-clock-o"></i> Marzipan</a>      </li>      <li class="nav-item  filter">         <a class="nav-link" href="#"><i class="fa fa-fw fa-tags"></i> Cakes and Muffins</a>      </li>      <li class="nav-item  filter">         <span class="navbar-brand">Categories</span>      </li>      <li class="nav-item ">         <a class="nav-link nav-link-collapse collapsed" data-toggle="collapse" href="#collapseComponents"><i class="fa fa-fw fa-flask"></i> Cars</a>         <ul class="sidebar-second-level collapse" id="collapseComponents">            <li>               <a class="nav-link-collapse collapsed" data-toggle="collapse" href="#collapseMulti2">American</a>               <ul class="sidebar-third-level collapse" id="collapseMulti2">                  <li>                     <a href="#">Ford</a>                  </li>                  <li>                     <a href="#">GMC</a>                  </li>               </ul>            </li>            <li>               <a class="nav-link-collapse collapsed" data-toggle="collapse" href="#collapseMulti3">European</a>               <ul class="sidebar-third-level collapse" id="collapseMulti3">                  <li>                     <a href="#">BMW</a>                  </li>                  <li>                     <a href="#">Audi</a>                  </li>               </ul>            </li>         </ul>      </li>      </div>   </ul>

My updated code:

// Case insensitive method for filterjQuery.expr[':'].casecontains = (a, b, c) => jQuery(a).text().toUpperCase().indexOf(c[3].toUpperCase()) >= 0;$('.search-filter').on('keyup', function () {            var input = $('.search-filter').val();                        console.log('input: '+input);            if (input.length != 0) {             // first hide the div #link-content lists from view            $('#link-content li').hide();            // but secretly unhide the collapsed links            // using .show, so the nested uls can be viewed            $('#link-content li.nav-item ul').show();            // then filter in the matching links only            $('#link-content li:casecontains("'+input+'")').show();            } else {            // secretly unhide the collapsed links            $('#link-content li.nav-item ul').hide();              // if search is empty, show the div and reset columns            $('#link-content li').show();            }        });

Here is a fiddle with the working example that opens any hidden links (collapsed class in boostrap 4).


If you remove the:

toLowerCase();

Everything matches perfectly if you type it perfectly. The issue is that you make the search term lower case, but it's not matching against lower case words. So when you type calculator, it doesn't match because the actual nav item shows as Calculator, with a capital c.

So you can either make the nav items lower case as well, via HTML or JavaScript, or you go about it in a different way, i.e. using IDs, but that would cause issues if the site is dynamic.

Bit of a weird work around may be to capitalize the first letters of each word so it actually matches the HTML. Take a look at How to capitalize first letter of each word, like a 2-word city?