I better blog about this before I forget how to do it. I recently worked on a project where I had to find a way to filter the results on a page using jQuery and custom HTML namespace selectors through a search box. There may be plenty of ways of doing this – probably a better one is to bind the keyup event of the input form field to an Ajax call that fetches the records from the server. For simplicity’s sake, I’ll go through an example of how to do this without any server queries, by using jQuery to filter the already displayed content on the client side.
The HTML
So let’s start with our HTML. This is basic stuff: we set up our page structure, include the jQuery file, create a form with just one text input field which will be used for searching, and a bunch of UL-LIs for listing out the contacts. We’ll assume that each contact has a name, phone and email address which we want to make searchable. We’ll also give our LIs a class which will make it easier to select them through jQuery and also to style them through CSS.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:custom="www.evagoras.com"> <head> <title>jQuery custom namespace selectors for filtering | evagoras.com</title></p> <meta http-equiv="Content-type" content="text/html;charset=UTF-8" /> <script type="text/javascript" src="jquery-1.5.min.js"></script> </head> <body> <!-- BEGIN: Search form. --> <form id="search-form" action=""> <label>search:</label> <input type="text" name="searchField" /> </form> <!-- END: Search form. --> <!-- BEGIN: Contacts listing. --> <ul id="contacts-listing"> <li class="contact" custom:searchtext="bob black 829-710-1405 bob.black@evagoras.com"> Bob Black | 829-710-1405 | bob.black@evagoras.com </li> <li class="contact" custom:searchtext="bob charalambous 339-171-2366 bob.charalambous@gmail.com"> Bob Charalambous | 339-171-2366 | bob.charalambous@gmail.com </li> <li class="contact" custom:searchtext="bob smith 529-873-6960 bob.smith@hotmail.com"> Bob Smith | 529-873-6960 | bob.smith@hotmail.com </li> <li class="contact" custom:searchtext="bob solano 919-278-5528 bob.solano@evagoras.com"> Bob Solano | 919-278-5528 | bob.solano@evagoras.com </li> <li class="contact" custom:searchtext="darth knight 715-257-7275 darth.knight@hotmail.com"> Darth Knight | 715-257-7275 | darth.knight@hotmail.com </li> <li class="contact" custom:searchtext="darth minets 456-194-1747 darth.minets@hotmail.com"> Darth Minets | 456-194-1747 | darth.minets@hotmail.com </li> <li class="contact" custom:searchtext="evagoras klekamp 603-483-2882 evagoras.klekamp@evagoras.com"> Evagoras Klekamp | 603-483-2882 | evagoras.klekamp@evagoras.com </li> <li class="contact" custom:searchtext="evagoras klekamp 399-934-8366 evagoras.klekamp@yahoo.com"> Evagoras Klekamp | 399-934-8366 | evagoras.klekamp@yahoo.com </li> <li class="contact" custom:searchtext="evagoras kouttouki 652-146-6760 evagoras.kouttouki@gmail.com"> Evagoras Kouttouki | 652-146-6760 | evagoras.kouttouki@gmail.com </li> <li class="contact" custom:searchtext="evagoras vader 271-553-9446 evagoras.vader@evagoras.com"> Evagoras Vader | 271-553-9446 | evagoras.vader@evagoras.com </li> <li class="contact" custom:searchtext="evagoras quintero 468-942-4463 evagoras.quintero@gmail.com"> Evagoras Quintero | 468-942-4463 | evagoras.quintero@gmail.com </li> </ul> <!-- END: Contacts listing. --> </body> </html>
So the first thing we need to do is set up our customized namespace. I decided to give all my custom HTML properties a prefix of “custom“. Therefore, I need to add this to my HTML declaration like so:
<html xmlns=”http://www.w3.org/1999/xhtml” xmlns:custom=”www.evagoras.com”>
I believe the domain you choose can be anything you like, and it doesn’t even have to be the same domain that the page is running under. It is however necessary to use something there, if you want your XHTML to pass the W3C validation.
The second thing we need to do is add the custom attributes inside our HTML. Since I am searching through my contact list, I created an attribute called “searchtext” which holds all the information that I want to make searchable and lives under the “custom” namespace:
<li custom:searchtext=”evagoras kouttouki 652-146-6760 evagoras.kouttouki@gmail.com”>…
The contents of this custom field are all in lowercase to make it consistent with my JavaScript function below.
The JavaScript
We then hook up our form input field to jQuery by binding it to the “keyup” listener which will run our search when a user types something in. The code first:
<script language="JavaScript"> // on document load $(function() { // Set up a listener when user types in the search box. $( '#search-form input' ).keyup( function() { // Get the string that was entered and make it lowercase. var searchString = $( this ).val().toLowerCase(); // The user actually typed something. if ( searchString.length > 0 ) { // Hide all the contacts. $( 'li.contact' ).hide(); /* Then display those that match the search criteria. This is done entirely client side to make it faster. We filter the results by using the CUSTOM attribute which we created in our namespace and used inside our HTML. */ $( 'li.contact[custom\\:searchtext*="' + EscapeExpression( searchString ) + '"]' ).show(); } } ); /* A string replacement regular expression that helps when entering non alphanumeric characters in the search form. */ function EscapeExpression( str ) { return str.replace(/([#;&,\.\+\*\~':"\!\^$\[\]\(\)=>\|])/g, "\\$1"); } }); </script>
When we detect that the user has started typing in the search form, we first hide all the LIs with class “contact“, and then display only those that match the search criteria. The most important line of the code is this:
$( ‘li.contact[custom\\:searchtext*=”‘ + EscapeExpression( searchString ) + ‘”]‘ ).show();
Keep in mind that when using square bracket selectors in jQuery, i.e. [], you will need to escape the custom namespace attributes with two backward slashes just like I did.
So there you have it. I think of custom namespace attributes as a sort of a hack, but they work wonders with jQuery and as long as you make sure to define them properly in your HTML document, then they should pass all XHTML validators as well. Please keep in mind that unless you’re actually serving the document as an XML Content-Type, all of your namespace stuff isn’t actually using namespaces anyway – at the end of the day this is all just a hack. In [X]HTML5 they are thinking of allowing custom attributes which will start with “data-“. In the meantime you may decide to hide your attribute in other HTML attributes, like for example the class definition:
<div class="customsearchtext-evagoras">...</div>
Thank you so much for this post; it was exactly what I was looking for!
One small correction.. I think you meant for each li to have the ‘contact’ class in it.
@Ville
Glad to hear you found it useful. You are right of course about forgetting to add the ‘contact’ class inside of each LI. The downloadable code is correct, but the post was indeed missing the class. I have corrected the post by adding it in. Thanks for letting me know.