Why does my jQuery search functionality only work once?

时间:2015-12-10 01:26:08

标签: jquery html css

I have a piece of code which will search for then scroll to and highlight a piece of text

jsFiddle: http://jsfiddle.net/z7fjW/137/

However, this piece of functionality will only work once, then no more searches can be performed. It doesn't seem to be removing the previously highlighted search sp perhaps something to do with this part?

$('.highlighted').removeClass('highlighted');     //Remove old search highlights
                $(selector).html($(selector).html()
                    .replace(searchTermRegEx, "<span class='highlighted'>"+searchTerm+"</span>"));

I'm not quite sure what's causing this so anybody help would be appreciated.

Thanks.

1 个答案:

答案 0 :(得分:2)

Here: http://jsfiddle.net/z7fjW/682/

This is super weird, i can't understand it. I found a workaround using delegated events, but will keep investigating until i find the reason the event only fires once.

$('body').on('click','#search-button',function() {
        if(!searchAndHighlight($('#search-term').val())) {
            alert("No results found");
        }
    });

EDIT: ok!! Once i figured it out it becomes fairly obvious. With this code

$(selector).html($(selector).html()
                    .replace(searchTermRegEx, "<span class='highlighted'>"+searchTerm+"</span>"));

The selector is set to body. You then call html() on the entire body, only to reinsert the same html with the addition of the span. The click listener was bound to the #search-button element. Because you overwrote the entire html of the body, you also overwrote the click listener. The tricky part for me was that the html looked exactly the same in the Chrome inspector, so it wasn't immediately obvious that the listener was unbound.

This explains why my workaround worked, because with event delegation the listener is attached to the body, when it detects a click, only then does jquery look for #search-button.

I would avoid rewriting the entire html of the body.. because it causes headaches like this. Try using this instead,

var selector = selector || "#bodyContainer";   

Now you only overwrite #bodyContainer, instead of the entire body html. With this you can also use your original event listener.

Relevant Docs: http://api.jquery.com/html/#html2

When .html() is used to set an element's content, any content that was in that element is completely replaced by the new content. Additionally, jQuery removes other constructs such as data and event handlers from child elements before replacing those elements with the new content.

相关问题