Jump to content

client side search


Recommended Posts

I have a container div #divContainer that holds 1073 other div's with a class of .eachDiv. I have a text input #search-input where i search through each .eachDiv within #divContainer on the keyup event. The problem is that it seems a little laggy when I type, and I am not sure how to fix this. I realize it is iterating over a lot of items for each keyup which causes the slowness, and I was wondering if anyone had suggestions on how to improve the performance or my approach. I am using jQuery.

var collection = $('#divContainer .eachDiv');var search = function ($collection, searchPhrase) {	  $collection.each(function () {	  var divText = this.innerHTML.toLowerCase();		  this.style.display = 'block';		 if (divText.indexOf(searchPhrase.toLowerCase()) === -1) {			 this.style.display = 'none';		 }	});};$('#search-input').bind('keyup', function () {	var searchPhrase = this.value;	search(collection, searchPhrase);});

EDIT: i noticed that it isn't as slow in Chrome. It's not horrible in FF, but it is noticeable. Does Chrome have a faster JS engine?

Edited by big dave
Link to post
Share on other sites

The suggestion has merit. I normally dislike duplicating data, and if the data needs to appear in the DOM, I like to consider that my data structure. BUT iterating through the DOM is notoriously slow, especially when the numbers get big. Having a javascript data structure shadow the DOM structure might, in this case, speed things along.

Link to post
Share on other sites

would making them spans (inline) elements help any?I see the thought process behind converting it to an array, I wonder if it would just be adding another step. The collection is already an array, all you would be doing is looping through the same array and putting it into an array, to search through again (albeit in a narrower scope). It seems by that point you could have already found what you are looking for.I wonder bigdave, if you wrote the collection statement like this, would you only get an array of innerHTML values?

var collection = $('#divContainer .eachDiv').html();

@Ixzion + DDedit: I get what you mean. duplicate the content of the div's into a shadow data structure, and search that instead, and then based on the index of the match(es) found, hide/show the corresponding div. Nice idea. Thanks for clarifying for me DD, I didn't get it at first.

Edited by thescientist
Link to post
Share on other sites
I wonder bigdave, if you wrote the collection statement like this, would you only get an array of innerHTML values?
var collection = $('#divContainer .eachDiv').html();

[/s]

Doing that only returns the innerHTML of the first items in the collection.Looks like my best bet is to just duplicate data. I didn't want to do this because now the server has to iterate over the data twice, once to create the JS array, and another time to place the data within the DOM.
Link to post
Share on other sites

it can't be done in the same loop? Maybe I'm confused how you are getting this data to the client.If the server is creating the data, and the client is retrieving, during the rendering process you could initialize the indexes of each array simultaneously, setting the values to the shadow array, and rendering the divs.Or you could have the server save the data json encoded as the value of a hidden input, so all the client side script has to do is get that value and eval() it.

Edited by thescientist
Link to post
Share on other sites

OTOH, toggling all those display properties could also be a bottleneck. It might be useful to track the none-displayed divs and toggle only those (or it, if there's only one at a time) and any that must go from block to none.Or am I imagining this wrong?Do the display states of all 1000+ divs HAVE to be toggled, or is that (as I initially thought) a way of catching just 1 or a few arbitrary divs that need to be toggled? It's a technique commonly used when you need to toggle one or five or eight. Maybe it's bad news with 1000?

Link to post
Share on other sites

i get the feeling the elements disappear as the search gets narrowed down through each inputed value.

Link to post
Share on other sites
i get the feeling the elements disappear as the search gets narrowed down through each inputed value.
correct.I set the display to block on each iteration, and then hide it only if the text within that <div> does not contain the searchPhrase that the user inputted. I have to set the display to block on each iteration because if a term is not found on one search and the user presses the delete button to re-search, the hidden divs from the previous search stay hidden. That is why i always change it to 'block' before deciding whether i should hide it or not.
Link to post
Share on other sites

I don't have access to jQuery on the computer I'm using currently, but I'm wondering if this might help the script run faster? It may end up just being moving the issue from one end to another, though. I don't know how fast JQuery applies the .show(). Just thought I'd throw it out there.

var collection = $('#divContainer .eachDiv');var search = function ($collection, searchPhrase) {	  $collection.each(function () {	  var divText = this.innerHTML.toLowerCase();		  this.style.display = 'block'; // This line is thrown out for the .show() below		 if (divText.indexOf(searchPhrase.toLowerCase()) === -1) {			 this.style.display = 'none';		 }	});};$('#search-input').bind('keyup', function () {		$('#divContainer .eachDiv').show(); // This would automatically turn all divs on for every keystroke	var searchPhrase = this.value;	search(collection, searchPhrase);});

Link to post
Share on other sites

thanks, i'll try that on monday when i am back at work. my guess it that it will either stay the same or make it longer since i think jquery just loops over the wrapped set and sets the display property when the show() method is called. on another note, i just found out about the console.time() and console.timeEnd() commands in Firefox so I can see how long it takes to run the function on each keyup. pretty neat!

Link to post
Share on other sites
I don't have access to jQuery on the computer I'm using currently, but I'm wondering if this might help the script run faster? It may end up just being moving the issue from one end to another, though. I don't know how fast JQuery applies the .show(). Just thought I'd throw it out there.
var collection = $('#divContainer .eachDiv');var search = function ($collection, searchPhrase) {	  $collection.each(function () {	  var divText = this.innerHTML.toLowerCase();		  this.style.display = 'block'; // This line is thrown out for the .show() below		 if (divText.indexOf(searchPhrase.toLowerCase()) === -1) {			 this.style.display = 'none';		 }	});};$('#search-input').bind('keyup', function () {		$('#divContainer .eachDiv').show(); // This would automatically turn all divs on for every keystroke	var searchPhrase = this.value;	search(collection, searchPhrase);});

Just tried it and it actually makes it slower by about 10-12 milliseconds, which makes sense since it would have to perform 2 iterations. Since i am searching for a user-inputted keyword which can be contained anywhere within the value of each index of the array, i cant really think of any search algorithm that would apply to this. I might have to either paginate the result set or invoke the search() function once the user has stopped typing for a few seconds.
Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...