I'm sure this is a very basic mistake I'm making but I can't work out where I am going wrong.
In this basic fiddle example, you will see I have 5 divs. I'm trying to replace a word in the middle of each div with another word, but it seems to be copying the contents of the first div into all of the other ones, as you can see from the beginning post numbers.
The snippet of code I'm using to do this is
$('.post').each(function(){
$('em').html(
$('em').html().replace('in','hello')
);
});
Please can someone help me to see where I'm going wrong?
2 Answers 2
You are replacing each em text with the content of all the ems' text. html also accepts a function that you can use to reference this, or take the current html as a parameter:
$('.post em').html(function (idx, html){
return html.replace("in", "hello");
});
Your updated jsFiddle demo.
Comments
There's no need for .each - you can use the version of .text that takes a mutator function and does an implicit .each on each matching element. The mutator function is passed the original text, and the return value gets put back in its place:
replaceIn = function() {
$('.post em').text(function(ix, txt) {
return txt.replace(/\b(in)\b/g, 'hello');
});
}
See http://jsfiddle.net/alnitak/ZUQ4W/
I've used .text instead of .html because there's no HTML inside the matched elements.
Note the use of a regexp with the /g flag to ensure that all occurrences of "in" are replaced and the \b markers to ensure that it only matches whole words.
The string version of replace can only replace the first match in a string. Do feel free to use that instead if that's your intent, of course!
Also note that you must me very careful if you use this (or variants using .html) on elements with descendants, because outer elements get processed before inner elements and the operations on the outer element might make unexpected changes to the descendants. Chose your selector wisely so that only leaf nodes are altered!
Another good reason to avoid .html() is that if you serialise an element and then deserialise it again with .html() then any properties or events that have been set on that element will be lost. So far as possible changes to the DOM should be done without using HTML string manipulation!
To be on the safe side, use this:
replaceIn = function () {
$('.post em').contents().filter(function () {
return this.nodeType === 3;
}).each(function() {
// NB: DOM level 3 uses .textContent in preference to .nodeValue
this.nodeValue = this.nodeValue.replace(/\b(in)\b/g, 'hello');
});
}
which makes absolutely sure that any nested elements (e.g. an index tag!) can't be modified.