3
\$\begingroup\$

I looked at a search filter code code and edited it to catered to my functional needs. I understood most of the JavaScript except the extend method bit. Can someone explain that? Also, is this the best way to create such a filter? Please let me know of any ways to improve the code.

<style type="text/css">
/* Clearfix */
.display{display:block;}
.hidden{display:none;}
.clearfix:before, .clearfix:after {content: " ";display: table;}
.clearfix:after {clear: both;}
.clearfix {*zoom: 1;}

#brand-search{margin-bottom:10px;clear: both;border:1px solid #ccc;width:200px;}
#brand-search:hover{border:1px solid #666;}
#search-text {float:left;padding:6px;font-size:14px;color:#333;background:#eee;border:0 none;margin:0;outline:0;width:122px;}
.list-count {float:left;text-align:right;width:56px;padding:6px 10px 6px 0;color:#999;background:#eee;}
ul {float:left;width:100%;margin:0;padding:0;position:relative;}
li {float:left;clear:left;width:100%;margin:0;padding:0.5em 0.8em;list-style:none;background-color:#f2f2f2;border:1px solid #f2f2f2;cursor:pointer;color:#333;position:relative;z-index:2;}
li:hover {background-color:#fff;border:1px solid #ccc;}
.empty-item {color:#aaa;padding:0;border:none;text-align:center;float:left;clear:left;display:none;}
</style>

<section class="list-wrap">
<div id="brand-search" class="clearfix">
    <input type="text" id="search-text" placeholder="search">
    <span class="list-count"></span>
</div>
<ul id="list">
  <li>red</li>
  <li>orange</li>
  <li>yellow</li>
  <li>pink</li>
  <li>blue</li>
  <li>green</li>
  <li>violet</li>
  <li>purple</li>
  <li>Indigo</li>
  <li>grey</li>
  <li>white</li>
  <li>black</li>
  <span class="empty-item">No items to show..</span>
</ul>
</section>

<script>
var list = $('#list'),
itemCount = list.find('li').length;

// list current items number
$('.list-count').text(itemCount + ' items');

$("#search-text").keyup(function(){
    var searchBrand = $("#search-text").val(),
    listItem = list.children('li'),
    searchSplit = searchBrand.replace(/ /g, "'):containsi('");

//extends :contains to be case insensitive
$.extend($.expr[':'],{
    'containsi': function(elem, i, match, array){
        return (elem.textContent || elem.innerText || '').toLowerCase().indexOf((match[3] || "").toLowerCase()) >= 0;
    }
});

    $("#list li").not(":containsi('" + searchSplit + "')").each(function(e){
      $(this).addClass('hidden');
    });
    $("#list li:containsi('" + searchSplit + "')").each(function(e){
      $(this).removeClass('hidden');
    });

    //show .empty-item state text when no jobs found
    var itemCount = listItem.length - list.find('.hidden').length;

    $('.list-count').text(itemCount + ' items');
    if(itemCount == '0'){
      $('.empty-item').show();
    }
    else {
      $('.empty-item').hide();
    }
});  
</script>
\$\endgroup\$
3
\$\begingroup\$

The extend method is being applied to jQuery.expr which is the set of selectors jQuery will apply when selecting elements (see here) -- jQuery.expr[":"] are the pseudo selectors jQuery acknowledges. The extend is useful if you want to add multiple jQuery selectors succinctly but for adding pseudo selectors I think its just a norm noting you can also add the selector as below

//extends :contains to be case insensitive
$.expr[':'].containsi = function(elem, i, match, array){
    return (elem.textContent || elem.innerText || '').toLowerCase().indexOf((match[3] || "").toLowerCase()) >= 0;
};

One more note: you probably want to add your custom selectors near the top of your code (and definitely outside of your keyup event handler!) in case you want to use your selector somewhere else in your code.

Now some nitpicks

Your Javascript near the end becomes difficult to read because the formatting of your keyup handler. Try pasting your code through an automatic formatter and notice how much easier it will be to follow (eg http://prettydiff.com)

if(itemCount == '0'){ //dont compare to '0' mate we know its an integer as its the length of a collection
  $('.empty-item').show();
}
else {
  $('.empty-item').hide();
}

I would write that as simply: $('.empty-item').toggle(itemCount === 0);

You can also write the following code in this similar one liner:

$("#list li:containsi('" + searchSplit + "')").each(function(e) {
    $(this).removeClass('hidden');
});

//more elegant:
$("#list li:containsi('" + searchSplit + "')").removeClass('hidden');
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Hiya, I am using my code but abit more complicated with multiple lists. How do I searcg filter through the list and put the matching key search to be appended in first list only? \$\endgroup\$ – Niraj paul Apr 11 '14 at 15:34
  • \$\begingroup\$ Elaborate I don't understand what you're asking \$\endgroup\$ – megawac Apr 11 '14 at 19:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.