Search code examples
jquerysortingsearch

Searching menu and returned ordered results


  1. List item

I've got a menu system on my site that includes submenus.

I'm trying to add a search function that will allow my users to search across the entire menu and just show matching results. As they type the results are narrowed down until the required match is found.

I've got this working, but the results are not ordered alphabetically. If I enter the character h I get :

Watch    
Hate    
Hates

If I then enter a, I get:

Hates    
Hate

I'd like the results to come back ordered a to z.

Does anyone know how to do this ?

menu = $('#menu').html()

$("body").on('keyup', '#search', function(e) {
  searchfor = $(this).val()

  if (searchfor.length > 0) {
    $('#menu li').hide()

    $('.link').each(function(i, obj) {
      if (obj.text.search(new RegExp(searchfor, 'i')) > -1) {
        $('#menu').prepend($(this).closest('li').show())
      }
    })
  } else {
    $('#search').val('')
    $('#menu li').show()
    $('#menu').empty().append(menu)
  }

})
@import "bourbon";
@import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,300,600);
body {
  font-family: "Lato";
  font-size: 100%;
  overflow-y: scroll;
  font-family: sans-serif;
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  background-color: #fefefe;
}

a {
  text-decoration: none;
  @include transition(all 0.6s ease);
  &:hover {
    @include transition(all 0.6s ease);
  }
}

.app {
  height: 100vh;
}


/* -------------
Sidebar
----------------*/

.sidebar {
  position: absolute;
  //width: 33.3333%;
  width: 17em;
  height: 100%;
  top: 0;
  overflow: hidden;
  background-color: #19222a;
  -webkit-transform: translateZ(0);
  visibility: visible;
  -webkit-backface-visibility: hidden;
  header {
    background-color: #09f;
    width: 100%;
    display: block;
    padding: 0.75em 1em;
  }
}


/* -------------
Sidebar Nav
----------------*/

.sidebar-nav {
  position: fixed;
  //width: 13em;
  background-color: #19222a;
  height: 100%;
  font-weight: 400;
  font-size: 1.2em;
  overflow: auto;
  padding-bottom: 6em;
  z-index: 9;
  overflow: hidden;
  -webkit-overflow-scrolling: touch;
  ul {
    list-style: none;
    display: block;
    padding: 0;
    margin: 0;
    li {
      margin-left: 0;
      padding-left: 0;
      //min-width: 13em;
      display: inline-block;
      width: 100%;
      a {
        color: rgba(255, 255, 255, 0.9);
        font-size: 0.75em;
        padding: 1.05em 1em;
        position: relative;
        display: block;
        &:hover {
          background-color: rgba(0, 0, 0, 0.9);
          @include transition(all 0.6s ease);
        }
      }
      /* -------------
Sidebar: icons
----------------*/
      i {
        font-size: 1.8em;
        padding-right: 0.5em;
        width: 9em;
        display: inline;
        vertical-align: middle;
      }
    }
  }
  /* -------------
Chev elements
----------------*/
  &>ul>li>a:after {
    content: '\f125';
    font-family: ionicons;
    font-size: 0.5em;
    width: 10px;
    color: #fff;
    position: absolute;
    right: 0.75em;
    top: 45%;
  }
  /* -------------
Nav-Flyout
----------------*/
  & .nav-flyout {
    position: absolute;
    background-color: #080D11;
    z-index: 9;
    left: 2.5em;
    top: 0;
    height: 100vh;
    @include transform(translateX(100%));
    @include transition(all 0.5s ease);
    a:hover {
      background-color: rgba(255, 255, 255, 0.05)
    }
  }
  /* -------------
Hover
----------------*/
  & ul>li:hover {
    .nav-flyout {
      @include transform(translateX(0));
      @include transition(all 0.5s ease);
    }
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<section class="app">
  <aside class="sidebar">
    <nav class="sidebar-nav">
      <input type='text' id='search' value='' />
      <ul id='menu'>
        <li>
          <a href="#"><i class="ion-bag"></i> <span>Shop</span></a>
          <ul class="nav-flyout">
            <li>
              <a href="#" class='link' data-link='page1'><i class="ion-ios-color-filter-outline"></i>Derps</a>
            </li>
            <li>
              <a href="#" class='link' data-link='page2'><i class="ion-ios-clock-outline"></i>Times</a>
            </li>
            <li>
              <a href="#" class='link' data-link='page3'><i class="ion-android-star-outline"></i>Hates</a>
            </li>
            <li>
              <a href="#" class='link' data-link='page4'><i class="ion-heart-broken"></i>Beat</a>
            </li>
          </ul>
        </li>
        <li>
          <a href="#"><i class="ion-ios-settings"></i> <span class="">Controls</span></a>
          <ul class="nav-flyout">
            <li>
              <a href="#" class='link' data-link='page5'><i class="ion-ios-alarm-outline"></i>Watch</a>
            </li>
            <li>
              <a href="#" class='link' data-link='page6'><i class="ion-ios-camera-outline"></i>Creeper</a>
            </li>
            <li>
              <a href="#" class='link' data-link='page7'><i class="ion-ios-chatboxes-outline"></i>Hate</a>
            </li>
            <li>
              <a href="#" class='link' data-link='page8'><i class="ion-ios-cog-outline"></i>Grinder</a>
            </li>
          </ul>
        </li>
        <li>

      </ul>
    </nav>
  </aside>
</section>


Solution

  • First filter the elements that match the search string. Then sort that list of elements before calling .each() to insert them into the output list.

    menu = $('#menu').html()
    
    $("body").on('keyup', '#search', function(e) {
      let searchfor = $(this).val();
    
      if (searchfor.length > 0) {
        $('#menu li').hide();
        let regexp = new RegExp(searchfor, 'i');
        let filtered = $('.link').filter(function() {
          return regexp.test(this.innerText);
        });
        filtered.sort((l1, l2) => l2.innerText.localeCompare(l1.innerText))
          .each(function() {
            $('#menu').prepend($(this).closest('li').show())
          })
      } else {
        $('#search').val('')
        $('#menu li').show()
        $('#menu').empty().append(menu)
      }
    
    })
    @import "bourbon";
    @import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,300,600);
    body {
      font-family: "Lato";
      font-size: 100%;
      overflow-y: scroll;
      font-family: sans-serif;
      -ms-text-size-adjust: 100%;
      -webkit-text-size-adjust: 100%;
      -ms-text-size-adjust: 100%;
      -webkit-text-size-adjust: 100%;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      text-rendering: optimizeLegibility;
      background-color: #fefefe;
    }
    
    a {
      text-decoration: none;
      @include transition(all 0.6s ease);
      &:hover {
        @include transition(all 0.6s ease);
      }
    }
    
    .app {
      height: 100vh;
    }
    
    
    /* -------------
    Sidebar
    ----------------*/
    
    .sidebar {
      position: absolute;
      //width: 33.3333%;
      width: 17em;
      height: 100%;
      top: 0;
      overflow: hidden;
      background-color: #19222a;
      -webkit-transform: translateZ(0);
      visibility: visible;
      -webkit-backface-visibility: hidden;
      header {
        background-color: #09f;
        width: 100%;
        display: block;
        padding: 0.75em 1em;
      }
    }
    
    
    /* -------------
    Sidebar Nav
    ----------------*/
    
    .sidebar-nav {
      position: fixed;
      //width: 13em;
      background-color: #19222a;
      height: 100%;
      font-weight: 400;
      font-size: 1.2em;
      overflow: auto;
      padding-bottom: 6em;
      z-index: 9;
      overflow: hidden;
      -webkit-overflow-scrolling: touch;
      ul {
        list-style: none;
        display: block;
        padding: 0;
        margin: 0;
        li {
          margin-left: 0;
          padding-left: 0;
          //min-width: 13em;
          display: inline-block;
          width: 100%;
          a {
            color: rgba(255, 255, 255, 0.9);
            font-size: 0.75em;
            padding: 1.05em 1em;
            position: relative;
            display: block;
            &:hover {
              background-color: rgba(0, 0, 0, 0.9);
              @include transition(all 0.6s ease);
            }
          }
          /* -------------
    Sidebar: icons
    ----------------*/
          i {
            font-size: 1.8em;
            padding-right: 0.5em;
            width: 9em;
            display: inline;
            vertical-align: middle;
          }
        }
      }
      /* -------------
    Chev elements
    ----------------*/
      &>ul>li>a:after {
        content: '\f125';
        font-family: ionicons;
        font-size: 0.5em;
        width: 10px;
        color: #fff;
        position: absolute;
        right: 0.75em;
        top: 45%;
      }
      /* -------------
    Nav-Flyout
    ----------------*/
      & .nav-flyout {
        position: absolute;
        background-color: #080D11;
        z-index: 9;
        left: 2.5em;
        top: 0;
        height: 100vh;
        @include transform(translateX(100%));
        @include transition(all 0.5s ease);
        a:hover {
          background-color: rgba(255, 255, 255, 0.05)
        }
      }
      /* -------------
    Hover
    ----------------*/
      & ul>li:hover {
        .nav-flyout {
          @include transform(translateX(0));
          @include transition(all 0.5s ease);
        }
      }
    }
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
    <section class="app">
      <aside class="sidebar">
        <nav class="sidebar-nav">
          <input type='text' id='search' value='' />
          <ul id='menu'>
            <li>
              <a href="#"><i class="ion-bag"></i> <span>Shop</span></a>
              <ul class="nav-flyout">
                <li>
                  <a href="#" class='link' data-link='page1'><i class="ion-ios-color-filter-outline"></i>Derps</a>
                </li>
                <li>
                  <a href="#" class='link' data-link='page2'><i class="ion-ios-clock-outline"></i>Times</a>
                </li>
                <li>
                  <a href="#" class='link' data-link='page3'><i class="ion-android-star-outline"></i>Hates</a>
                </li>
                <li>
                  <a href="#" class='link' data-link='page4'><i class="ion-heart-broken"></i>Beat</a>
                </li>
              </ul>
            </li>
            <li>
              <a href="#"><i class="ion-ios-settings"></i> <span class="">Controls</span></a>
              <ul class="nav-flyout">
                <li>
                  <a href="#" class='link' data-link='page5'><i class="ion-ios-alarm-outline"></i>Watch</a>
                </li>
                <li>
                  <a href="#" class='link' data-link='page6'><i class="ion-ios-camera-outline"></i>Creeper</a>
                </li>
                <li>
                  <a href="#" class='link' data-link='page7'><i class="ion-ios-chatboxes-outline"></i>Hate</a>
                </li>
                <li>
                  <a href="#" class='link' data-link='page8'><i class="ion-ios-cog-outline"></i>Grinder</a>
                </li>
              </ul>
            </li>
            <li>
    
          </ul>
        </nav>
      </aside>
    </section>