Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery Live Search with Quicksilver Style in a Multi Select List Box

I am trying to get John Resig's jQuery Live Search with Quicksilver Style to work with a select multi form control. His code is based John Nunemaker's Work developing his quicksilver.js code.

The problem I am having is that within a select box only Firefox supports .hide() on option values, I can't figure out a snappy approach for IE, Safari, Opera and Chrome.

Here is an example, I have inlined John R's code but you will need to grab quicksilver.js and host it locally yourself. Again this works great in Firefox but the call to rows.hide() does nothing on other browsers.

I have tried wrapping the tags in in a div and hiding that but no luck.

Any ideas?

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  <title>LiveSearch</title>
  <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.js"></script> 
  <script type="text/javascript" src="../jquery/quicksilver.js"></script>

  <script type="text/javascript" charset="utf-8">
     $(document).ready(function() {
        $('#q').liveUpdate('#posts').focus();
     });

     jQuery.fn.liveUpdate = function(list){
       list = jQuery(list);

       if ( list.length ) {
           // Changed 'li' to 'option' below
           var rows = list.children('option'),
              cache = rows.map(function(){
              return this.innerHTML.toLowerCase();
              });

           this
               .keyup(filter).keyup()
               .parents('form').submit(function(){
                   return false;
               });
       }

       return this;

       function filter(){
           var term = jQuery.trim( jQuery(this).val().toLowerCase() ), scores = [];

           if ( !term ) {
               rows.show();
           } else {
               rows.hide();

               cache.each(function(i){
                   var score = this.score(term);
                   if (score > 0) { scores.push([score, i]); }
               });

               jQuery.each(scores.sort(function(a, b){return b[0] - a[0];}), function(){
                   jQuery(rows[ this[1] ]).show();
               });
           }
       }
     };

  </script>
</head>
<body>

<form method="get" autocomplete="off" action="">

  <div>
     <input type="text" value="" name="q" id="q"><br><br>

     <select id="posts" multiple name="choices" SIZE="10" style="width: 250px">
        <option value="1">The Well-Designed Web</option>
        <option value="2">Welcome John Nunemaker</option>
        <option value="3">Sidebar Creative: The Next Steps</option>
        <option value="4">The Web/Desktop Divide</option>
        <option value="5">2007 in Review</option>
        <option value="6">Don't Complicate the Solution</option>
        <option value="7">Blog to Business</option>
        <option value="8">Single Line CSS</option>
        <option value="9">The Great Divide</option>
        <option value="10">What's in a Name?</option>
     </select>

  </div>


</form>

</body>
</html>
like image 423
kevink Avatar asked Mar 08 '09 17:03

kevink


1 Answers

The best approach is just to add and remove options from the DOM.

Like this:

  <script type="text/javascript" charset="utf-8">
     $(document).ready(function() {
        $('#q').liveUpdate('#posts').focus();
     });

     jQuery.fn.liveUpdate = function(list){
       list = jQuery(list);

       if ( list.length ) {
               // Changed 'li' to 'option' below
               var rows = list.children('option'),
                  cache = rows.map(function(){
                  return this.innerHTML.toLowerCase();
                  });

               var all = rows;
               all.each(function(i){
                  $(this).attr("itext", this.innerHTML.toLowerCase());
               });

               this
                       .keyup(filter).keyup()
                       .parents('form').submit(function(){
                               return false;
                       });
       }

       return this;

       function filter(){
               var term = jQuery.trim( jQuery(this).val().toLowerCase() ), scores = [];

               if ( !term ) {
                       list.append(all);
               } else {
                       rows.remove();

                       all.each(function(i){
                               var score = $(this).attr("itext").score(term);
                               if (score > 0) { scores.push([score, i]); }
                       });

                       jQuery.each(scores.sort(function(a, b){return b[0] - a[0];}), function(){
                               list.append(all[this[1]]);
                       });

                       rows = list.children('option');
               }
       }
     };

  </script>

EDIT:

Need to score over array "all" rather than rows.

like image 96
Joel Avatar answered Oct 16 '22 16:10

Joel