Laggy string search, how can it be improved? - javascript

I have a function that i use to search for a spesific string in the innerText of elements with a certain class name. When it finds a match it gives that element a display of block to show and if not display none to hide. When i use this to search (i have about 3 thousand elements with same class) it takes a few seconds (about 5s) before it completes. Is there a more performance based way to write this code and maybe cut a second or two?
function searchClass(ClassName, Value){
var c = document.getElementsByClassName(ClassName);
var val = Value.toLowerCase().trim();
for(var i=0;i<c.length;i++){
if(c[i].innerText.toLowerCase().trim().indexOf(val) > -1){
c[i].style.display = "block";
}else{
c[i].style.display = "none";
}
}
}
PS. there is a keyup event that triggers the function.
EDIT: (solution) My search is instantly alot faster just by changing innerText to textContent and some small changes thanks to comments!

pre-increment is faster than post-increment when you don't need the previous value, and you don't, so switch to pre-increment in the for loop (although id expect today's competitve js engines to auto-optimize this, gcc has done this for ages on -O1 and higher)
also, unless you have a lot of script elements, textContent should be a lot faster than innerText, so switch to textContent... other than that, i don't see much room for improvement

Related

Scraping data from HTML using JavaScript RegExp [duplicate]

I'm trying to figure out how to, in raw javascript (no jQuery, etc.), find an element with specific text and modify that text.
My first incarnation of the solution... is less than adequate. What I did was basically:
var x = document.body.innerHTML;
x.replace(/regular-expression/,"text");
document.body.innerHTML = x;
Naively I thought I succeeded with flying colors, especially since it was so simple. So then I added an image to my example and thought I could check every 5 seconds (because this string may enter the DOM dynamically)... and the image flickered every 5 seconds.
Oops.
So, there has to be a correct way to do this. A way that specifically singles out a specific DOM element and updates the text portion of that DOM element.
Now, there's always "recursively search through the children till you find the deepest child with the string" approach, which I want to avoid. And even then, I'm skeptical about "changing the innerHTML to something different" being the correct way to update a DOM element.
So, what's the correct way to search through the DOM for a string? And what's the correct way to update a DOM element's text?
Now, there's always "recursively search through the children till you find the deepest child with the string" approach, which I want to avoid.
I want to search for an element in an unordered random list. Now, there's a "go through all the elements till you find what you're looking for approach", which I want to avoid.
Old-timer magno tape, record, listen, meditate.
Btw, see: Find and replace text with JavaScript on James Padolsey's github
(also hig blog articles explaining it)
Edit: Changed querySelectorAll to getElementsByTagName from RobG's suggestion.
You can use the getElementsByTagName function to grab all of the tags on the page. From there, you can check their children and see if they have any Text Nodes as children. If they do, you'd then look at their text and see if it matches what you need. Here is an example that will print out the text of every Text Node in your document with the console object:
var elms = document.getElementsByTagName("*"),
len = elms.length;
for(var ii = 0; ii < len; ii++) {
var myChildred = elms[ii].childNodes;
len2 = myChildred.length;
for (var jj = 0; jj < len2; jj++) {
if(myChildred[jj].nodeType === 3) {
console.log(myChildred[jj].nodeValue);
// example on update a text node's value
myChildred[jj].nodeValue = myChildred[jj].nodeValue.replace(/test/,"123");
}
}
}
To update a DOM element's text, simple update the nodeValue property of the Text Node.
Don't use innerHTML with a regular expression, it will almost certainly fail for non-trivial content. Also, there are still differences in how browsers generate it from the live DOM. Replacing the innerHTML will also remove any event listeners added as element properties (i.e. like element.onclick = fn).
It is best if you can have the string enclosed in an element with an attribute or property you can search on (id, class, etc.) but failing that, a search of text nodes is the best approach.
Edit
Attempting a general purpose text selection function for an HTML document may result in a very complex algorithm since the string could be part of a complex structure, e.g.:
<h1>Some <span class="foo"><em>s</em>pecial</span> heading</h1>
Searching for the string "special heading" is tricky as it is split over 2 elements. Wrapping it another element (say for highlighting) is also not trivial since the resulting DOM structure must be valid. For example, the text matching "some special" in the above could be wrapped in a span but not a div.
Any such function must be accompanied by documentation stating its limitations and most appropriate use.
Forget regular expressions.
Iterate over each text node (and doing it recursively will be the most elegant) and modify the text nodes if the text is found. If just looking for a string, you can use indexOf().
x.replace(/regular-expression/,"text");
will return a value so
var y = x.replace(/regular-expression/,"text");
now you can assign new value.
document.body.innerHTML = y;
Bu you want to think about this, you dont't want to get the whole body just to change one small piece of code, why not get the content of a div or any element and so on
example:
<p id='paragraph'>
... some text here ...
</p>
now you can use javascript
var para = document.getElementById('paragraph').innerHTML;
var newPara = para.replace(/regex/,'new content');
para.innerHTML = newPara;
This should be the simplest way.

Safely / completely remove element from DOM [duplicate]

When removing an element with standard JavaScript, you must go to its parent first:
var element = document.getElementById("element-id");
element.parentNode.removeChild(element);
Having to go to the parent node first seems a bit odd to me, is there a reason JavaScript works like this?
I know that augmenting native DOM functions isn't always the best or most popular solution, but this works fine for modern browsers.
Element.prototype.remove = function() {
this.parentElement.removeChild(this);
}
NodeList.prototype.remove = HTMLCollection.prototype.remove = function() {
for(var i = this.length - 1; i >= 0; i--) {
if(this[i] && this[i].parentElement) {
this[i].parentElement.removeChild(this[i]);
}
}
}
And then you can remove elements like this
document.getElementById("my-element").remove();
or
document.getElementsByClassName("my-elements").remove();
Note: this solution doesn't work for IE 7 and below. For more info about extending the DOM read this article.
EDIT: Reviewing my answer in 2019, node.remove() has come to the rescue and can be used as follows (without the polyfill above):
document.getElementById("my-element").remove();
or
[...document.getElementsByClassName("my-elements")].map(n => n && n.remove());
These functions are available in all modern browsers (not IE). Read more on MDN.
Crossbrowser and IE >= 11:
document.getElementById("element-id").outerHTML = "";
You could make a remove function so that you wouldn't have to think about it every time:
function removeElement(id) {
var elem = document.getElementById(id);
return elem.parentNode.removeChild(elem);
}
Update 2011
This was added to the DOM spec back in 2011, so you can just use:
element.remove()
The DOM is organized in a tree of nodes, where each node has a value, along with a list of references to its child nodes. So element.parentNode.removeChild(element) mimics exactly what is happening internally: First you go the parent node, then remove the reference to the child node.
As of DOM4, a helper function is provided to do the same thing: element.remove(). This works in 96% of browsers (as of 2020), but not IE 11.
If you need to support older browsers, you can:
Remove elements via the parent node
Modify the native DOM functions, as in Johan Dettmar's answer, or
Use a DOM4 polyfill.
It's what the DOM supports. Search that page for "remove" or "delete" and removeChild is the only one that removes a node.
For removing one element:
var elem = document.getElementById("yourid");
elem.parentElement.removeChild(elem);
For removing all the elements with for example a certain class name:
var list = document.getElementsByClassName("yourclassname");
for(var i = list.length - 1; 0 <= i; i--)
if(list[i] && list[i].parentElement)
list[i].parentElement.removeChild(list[i]);
you can just use element.remove()
You can directly remove that element by using remove() method of DOM.
here's an example:
let subsWrapper = document.getElementById("element_id");
subsWrapper.remove();
//OR directly.
document.getElementById("element_id").remove();
The ChildNode.remove() method removes the object from the tree it belongs to.
https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove
Here is a fiddle that shows how you can call document.getElementById('my-id').remove()
https://jsfiddle.net/52kp584L/
**
There is no need to extend NodeList. It has been implemented already.
**
According to DOM level 4 specs, which is the current version in development, there are some new handy mutation methods available: append(), prepend(), before(), after(), replace(), and remove().
https://catalin.red/removing-an-element-with-plain-javascript-remove-method/
You can simply use
document.getElementById("elementID").outerHTML="";
It works in all browsers, even on Internet Explorer.
Having to go to the parent node first seems a bit odd to me, is there a reason JavaScript works like this?
The function name is removeChild(), and how is it possible to remove the child when there's no parent? :)
On the other hand, you do not always have to call it as you have shown. element.parentNode is only a helper to get the parent node of the given node. If you already know the parent node, you can just use it like this:
Ex:
// Removing a specified element when knowing its parent node
var d = document.getElementById("top");
var d_nested = document.getElementById("nested");
var throwawayNode = d.removeChild(d_nested);
https://developer.mozilla.org/en-US/docs/Web/API/Node/removeChild
=========================================================
To add something more:
Some answers have pointed out that instead of using parentNode.removeChild(child);, you can use elem.remove();. But as I have noticed, there is a difference between the two functions, and it's not mentioned in those answers.
If you use removeChild(), it will return a reference to the removed node.
var removedChild = element.parentNode.removeChild(element);
console.log(removedChild); //will print the removed child.
But if you use elem.remove();, it won't return you the reference.
var el = document.getElementById('Example');
var removedChild = el.remove(); //undefined
https://developer.mozilla.org/en-US/docs/Web/API/ChildNode/remove
This behavior can be observed in Chrome and FF. I believe It's worth noticing :)
Hope my answer adds some value to the question and will be helpful!!
Functions that use ele.parentNode.removeChild(ele) won't work for elements you've created but not yet inserted into the HTML. Libraries like jQuery and Prototype wisely use a method like the following to evade that limitation.
_limbo = document.createElement('div');
function deleteElement(ele){
_limbo.appendChild(ele);
_limbo.removeChild(ele);
}
I think JavaScript works like that because the DOM's original designers held parent/child and previous/next navigation as a higher priority than the DHTML modifications that are so popular today. Being able to read from one <input type='text'> and write to another by relative location in the DOM was useful in the mid-90s, a time when the dynamic generation of entire HTML forms or interactive GUI elements was barely a twinkle in some developer's eye.
Shortest
I improve Sai Sunder answer because OP uses ID which allows to avoid getElementById:
elementId.remove();
box2.remove(); // remove BOX 2
this["box-3"].remove(); // remove BOX 3 (for Id with 'minus' character)
<div id="box1">My BOX 1</div>
<div id="box2">My BOX 2</div>
<div id="box-3">My BOX 3</div>
<div id="box4">My BOX 4</div>
Having to go to the parent node first seems a bit odd to me, is there
a reason JavaScript works like this?
IMHO: The reason for this is the same as I've seen in other environments: You are performing an action based on your "link" to something. You can't delete it while you're linked to it.
Like cutting a tree limb. Sit on the side closest to the tree while cutting or the result will be ... unfortunate (although funny).
From what I understand, removing a node directly does not work in Firefox, only Internet Explorer. So, to support Firefox, you have to go up to the parent to remove it's child.
Ref: http://chiragrdarji.wordpress.com/2007/03/16/removedelete-element-from-page-using-javascript-working-in-firefoxieopera/
This one actually comes from Firefox... for once, IE was ahead of the pack and allowed the removal of an element directly.
This is just my assumption, but I believe the reason that you must remove a child through the parent is due to an issue with the way Firefox handled the reference.
If you call an object to commit hari-kari directly, then immediately after it dies, you are still holding that reference to it. This has the potential to create several nasty bugs... such as failing to remove it, removing it but keeping references to it that appear valid, or simply a memory leak.
I believe that when they realized the issue, the workaround was to remove an element through its parent because when the element is gone, you are now simply holding a reference to the parent. This would stop all that unpleasantness, and (if closing down a tree node by node, for example) would 'zip-up' rather nicely.
It should be an easily fixable bug, but as with many other things in web programming, the release was probably rushed, leading to this... and by the time the next version came around, enough people were using it that changing this would lead to breaking a bunch of code.
Again, all of this is simply my guesswork.
I do, however, look forward to the day when web programming finally gets a full spring cleaning, all these strange little idiosyncracies get cleaned up, and everyone starts playing by the same rules.
Probably the day after my robot servant sues me for back wages.
// http://javascript.crockford.com/memory/leak.html
// cleans dom element to prevent memory leaks
function domPurge(d) {
var a = d.attributes, i, l, n;
if (a) {
for (i = a.length - 1; i >= 0; i -= 1) {
n = a[i].name;
if (typeof d[n] === 'function') {
d[n] = null;
}
}
}
a = d.childNodes;
if (a) {
l = a.length;
for (i = 0; i < l; i += 1) {
domPurge(d.childNodes[i]);
}
}
}
function domRemove(id) {
var elem = document.getElementById(id);
domPurge(elem);
return elem.parentNode.removeChild(elem);
}
This is the best function to remove an element without script error:
function Remove(EId)
{
return(EObj=document.getElementById(EId))?EObj.parentNode.removeChild(EObj):false;
}
Note to EObj=document.getElementById(EId).
This is ONE equal sign not ==.
if element EId exists then the function removes it, otherwise it returns false, not error.

Javascript taking too long to run

I have a script that is taking too long to run and that is causing me This error on ie : a script on this page is causing internet explorer to run slowly.
I have read other threads concerning this error and have learned that there is a way to by pass it by putting a time out after a certain number of iterations.
Can u help me apply a time out on the following function please ?
Basically each time i find a hidden imput of type submit or radio i want to remove and i have a lot of them . Please do not question why do i have a lots of hidden imputs. I did it bc i needed it just help me put a time out please so i wont have the JS error. Thank you
$('input:hidden').each(function(){
var name = $(this).attr('name');
if($("[name='"+name+"']").length >1){
if($(this).attr('type')!=='radio' && $(this).attr('type')!=='submit'){
$(this).remove();
}
}
});
One of the exemples i found : Bypassing IE's long-running script warning using setTimeout
You may want to add input to your jquery selector to filter out only input tags.
if($("input[name='"+name+"']").length >1){
Here's the same code optimised a bit without (yet) using setTimeout():
var $hidden = $('input:hidden'),
el;
for (var i = 0; i < $hidden.length; i++) {
el = $hidden[i];
if(el.type!=='radio' && el.type!=='submit'
&& $("[name='" + el.name + "']").length >1) {
$(el).remove();
}
}
Notice that now there is a maximum of three function calls per iteration, whereas the original code had up to ten function calls per iteration. There's no need for, say, $(this).attr('type') (two function calls) when you can just say this.type (no function calls).
Also, the .remove() only happens if three conditions are true, the two type tests and check for other elements of the same name. Do the type tests first, because they're quick, and only bother doing the slow check for other elements if the type part passes. (JS's && doesn't evaluate the right-hand operand if the left-hand one is falsy.)
Or with setTimeout():
var $hidden = $('input:hidden'),
i = 0,
el;
function doNext() {
if (i < $hidden.length) {
el = $hidden[i];
if(el.type!=='radio' && el.type!=='submit'
&& $("[name='" + el.name + "']").length >1) {
$(el).remove();
}
i++;
setTimeout(doNext, 0);
}
}
doNext();
You could improve either version by changing $("[name='" + el.name + "']") to specify a specific element type, e.g., if you are only doing inputs use $("input[name='" + el.name + "']"). Also you could limit by some container, e.g., if those inputs are all in a form or something.
It looks like the example you cited is exactly what you need. I think if you take your code and replace the while loop in the example (keep the if statement for checking the batch size), you're basically done. You just need the jQuery version of breaking out of a loop.
To risk stating the obvious; traversing through the DOM looking for matches to these CSS selectors is what's making your code slow. You can cut down the amount of work it's doing with a few simple tricks:
Are these fields inside a specific element? If so you can narrow the search by including that element in the selector.
e.g:
$('#container input:hidden').each(function(){
...
You can also narrow the number of fields that are checked for the name attribute
e.g:
if($("#container input[name='"+name+"']").length >1){
I'm also unclear why you're searching again with $("[name='"+name+"']").length >1once you've found the hidden element. You didn't explain that requirement. If you don't need that then you'll speed this up hugely by taking it out.
$('#container input:hidden').each(function(){
var name = $(this).attr('name');
if($(this).attr('type')!=='radio' && $(this).attr('type')!=='submit'){
$(this).remove();
}
});
If you do need it, and I'd be curious to know why, but the best approach might be to restructure the code so that it only checks the number of inputs for a given name once, and removes them all in one go.
Try this:
$("[type=hidden]").remove(); // at the place of each loop
It will take a short time to delete all hidden fields.
I hope it will help.
JSFiddle example

What is better, appending new elements via DOM functions, or appending strings with HTML tags?

I have seen a few different methods to add elements to the DOM. The most prevelent seem to be, for example, either
document.getElementById('foo').innerHTML ='<p>Here is a brand new paragraph!</p>';
or
newElement = document.createElement('p');
elementText = document.createTextNode('Here is a brand new parahraph!');
newElement.appendChild(elementText);
document.getElementById('foo').appendChild(newElement);
but I'm not sure of the advantages to doing either one. Is there a rule of thumb as to when one should be done over the other, or is one of these just flat out wrong?
Some notes:
Using innerHTML is faster in IE, but slower in chrome + firefox. Here's one benchmark showing this with a constantly varying set of <div>s + <p>s; here's a benchmark showing this for a constant, simple <table>.
On the other hand, the DOM methods are the traditional standard -- innerHTML is standardized in HTML5 -- and allow you to retain references to the newly created elements, so that you can modify them later.
Because innerHTML is fast (enough), concise, and easy to use, it's tempting to lean on it for every situation. But beware that using innerHTML detaches all existing DOM nodes from the document. Here's an example you can test on this page.
First, let's create a function that lets us test whether a node is on the page:
function contains(parent, descendant) {
return Boolean(parent.compareDocumentPosition(descendant) & 16);
}
This will return true if parent contains descendant. Test it like this:
var p = document.getElementById("portalLink")
console.log(contains(document, p)); // true
document.body.innerHTML += "<p>It's clobberin' time!</p>";
console.log(contains(document, p)); // false
p = document.getElementById("portalLink")
console.log(contains(document, p)); // true
This will print:
true
false
true
It may not look like our use of innerHTML should have affected our reference to the portalLink element, but it does. It needs to be retrieved again for proper use.
There are a number of differences:
innerHTML has only been standardised by the W3C for HTML 5; even though it has been a de facto standard for some time now across all popular browsers, technically in HTML 4 it's a vendor extension that standards-adherent developers would never be caught dead using. On the other hand, it's much more convenient and practically it's supported by all browsers.
innerHTML replaces the current content of the element (it does not let you modify it). But again, you gain in convenience if you don't mind this limitation.
innerHTML has been measured to be much faster (admittedly, that test involves older versions browsers that are not widely used today).
innerHTML might represent a security risk (XSS) if it's set to a user-supplied value that has not been properly encoded (e.g. el.innerHTML = '<script>...').
Based on the above, it seems that a practical conclusion might be:
If you don't mind the fact that innerHTML is a bit limiting (only total replacement of DOM sub-tree rooted at target element) and you don't risk a vulnerability through injecting user-supplied content, use that. Otherwise, go with DOM.
Though this is an old thread, one thing that is not mentioned is the while innerHTML can be faster, care should be taken. Using innerHTML will render every child of the modified element, old and new alike. As such, one single innerHTML assignment is faster (slightly) than DOM create/append, but multiple innerHTML will definetly be slower.
For example:
for(let i=0; i < 10; i++)
document.body.innerHTML+='<div>some text</div>';
will be nearly nearly 5x slower than
let html = '';
for(let i=0; i < 10; i++)
html += '<div>some text</div>';
document.body.innerHTML = html;
Since innerHTML assignment is letting the browser natively create/append elements, the second methods results in 10 elements being natively created/appended, while the firstmethod results in 55 elements being created/appended (and 45 being destroyed): 1 element created on first loop-iteration, 2 elements created on the second loop-iteration (the original being destroyed), 3 elements created on the third loop-iteration (the previous 2 being destroyed), and so on.
If you use innerHTML for speed, you must make sure to create the entire html string first before making the innerHTML assignment, such as creating fresh DOM containers/elements. innerHTML, on the other hand, is a performance loser when appending any container with existing childNodes, especially those with large number of childNodes.
According to this benchmark data, you will receive much faster results with innerHTML than creating DOM elements. It's especially clear when using older IE versions.
First one is straight forward, easier to read, less code and might be faster.
Second one gives you much more control over the element you create, i.e. makes it much easier to modify the new Element using JS (like attaching events, or, just use it in your code).
Second way is for "purist" who like "clean" code (no quick and dirty).
I say, use both, see what fits you better and go with it.
I always prefer readability unless the perf difference is extreme. In a one-off case of this, it probably will be a marginal difference.
In a one-off case like this, setting the innerHTML property will be easiest to read.
But if you are doing a lot of programmatic content generation in JavaScript, it is cleaner and easier to read and understand the DOM option.
Example:
Compare this innerHTML code:
http://jsfiddle.net/P8m3K/1/
// Takes input of a value between 1 and 26, inclusive,
// and converts it to the appropriate character
function alphaToChar(alpha)
{
return String.fromCharCode('a'.charCodeAt() + alpha - 1);
}
var content = "<ul>";
for(i = 0; i < 10; ++i)
{
content += "<li>";
for(j = 1; j <= 26; ++j)
{
content += "<a href=\"" + alphaToChar(j) + ".html\">"
+ alphaToChar(j)
+ "</a>";
}
content += "</li>";
}
document.getElementById("foo").innerHTML = content;
To this DOM code:
http://jsfiddle.net/q6GB8/1/
// Takes input of a value between 1 and 26, inclusive,
// and converts it to the appropriate character
function alphaToChar(alpha)
{
return String.fromCharCode('a'.charCodeAt() + alpha - 1);
}
var list = document.createElement("ul");
for(i = 0; i < 10; ++i)
{
var item = document.createElement("li");
for(j = 1; j <= 26; ++j)
{
var link = document.createElement("a");
link.setAttribute("href", alphaToChar(j) + ".html");
link.innerText = alphaToChar(j);
item.appendChild(link);
}
list.appendChild(item);
}
document.getElementById("foo").appendChild(list);
At this level they start to become quite similar length wise.
But the DOM code will be easier to maintain, and you're a bit less likely to make a typo or mistake that is hard to diagnose, like omitting a closing tag. Either your elements will be in your document, or they won't.
With more complicated scenarios (like building treed menus), you'll probably come out ahead with DOM code.
With scenarios where you have to append multiple types of content together to build a document with more heterogeneous content, it becomes a slam dunk. You don't have to ensure you call your child append code before calling the parent append code.
With scenarios where add, remove, or modify existing static content, DOM will usually win.
If you start doing complicated DOM modifications (one of the last things I mentioned), you'll definitely want to check out a library built around DOM modifications, like jQuery.

Finding the DOM element with specific text and modify it

I'm trying to figure out how to, in raw javascript (no jQuery, etc.), find an element with specific text and modify that text.
My first incarnation of the solution... is less than adequate. What I did was basically:
var x = document.body.innerHTML;
x.replace(/regular-expression/,"text");
document.body.innerHTML = x;
Naively I thought I succeeded with flying colors, especially since it was so simple. So then I added an image to my example and thought I could check every 5 seconds (because this string may enter the DOM dynamically)... and the image flickered every 5 seconds.
Oops.
So, there has to be a correct way to do this. A way that specifically singles out a specific DOM element and updates the text portion of that DOM element.
Now, there's always "recursively search through the children till you find the deepest child with the string" approach, which I want to avoid. And even then, I'm skeptical about "changing the innerHTML to something different" being the correct way to update a DOM element.
So, what's the correct way to search through the DOM for a string? And what's the correct way to update a DOM element's text?
Now, there's always "recursively search through the children till you find the deepest child with the string" approach, which I want to avoid.
I want to search for an element in an unordered random list. Now, there's a "go through all the elements till you find what you're looking for approach", which I want to avoid.
Old-timer magno tape, record, listen, meditate.
Btw, see: Find and replace text with JavaScript on James Padolsey's github
(also hig blog articles explaining it)
Edit: Changed querySelectorAll to getElementsByTagName from RobG's suggestion.
You can use the getElementsByTagName function to grab all of the tags on the page. From there, you can check their children and see if they have any Text Nodes as children. If they do, you'd then look at their text and see if it matches what you need. Here is an example that will print out the text of every Text Node in your document with the console object:
var elms = document.getElementsByTagName("*"),
len = elms.length;
for(var ii = 0; ii < len; ii++) {
var myChildred = elms[ii].childNodes;
len2 = myChildred.length;
for (var jj = 0; jj < len2; jj++) {
if(myChildred[jj].nodeType === 3) {
console.log(myChildred[jj].nodeValue);
// example on update a text node's value
myChildred[jj].nodeValue = myChildred[jj].nodeValue.replace(/test/,"123");
}
}
}
To update a DOM element's text, simple update the nodeValue property of the Text Node.
Don't use innerHTML with a regular expression, it will almost certainly fail for non-trivial content. Also, there are still differences in how browsers generate it from the live DOM. Replacing the innerHTML will also remove any event listeners added as element properties (i.e. like element.onclick = fn).
It is best if you can have the string enclosed in an element with an attribute or property you can search on (id, class, etc.) but failing that, a search of text nodes is the best approach.
Edit
Attempting a general purpose text selection function for an HTML document may result in a very complex algorithm since the string could be part of a complex structure, e.g.:
<h1>Some <span class="foo"><em>s</em>pecial</span> heading</h1>
Searching for the string "special heading" is tricky as it is split over 2 elements. Wrapping it another element (say for highlighting) is also not trivial since the resulting DOM structure must be valid. For example, the text matching "some special" in the above could be wrapped in a span but not a div.
Any such function must be accompanied by documentation stating its limitations and most appropriate use.
Forget regular expressions.
Iterate over each text node (and doing it recursively will be the most elegant) and modify the text nodes if the text is found. If just looking for a string, you can use indexOf().
x.replace(/regular-expression/,"text");
will return a value so
var y = x.replace(/regular-expression/,"text");
now you can assign new value.
document.body.innerHTML = y;
Bu you want to think about this, you dont't want to get the whole body just to change one small piece of code, why not get the content of a div or any element and so on
example:
<p id='paragraph'>
... some text here ...
</p>
now you can use javascript
var para = document.getElementById('paragraph').innerHTML;
var newPara = para.replace(/regex/,'new content');
para.innerHTML = newPara;
This should be the simplest way.

Categories