I have a piece of Javascript code that locates the single table in the DOM then tries to manipulate its first child, the thead (actually, it iterates though the children of that child, the tr entries but that's not important to the question). The code to do this is:
var tableNode = document.getElementById("table").firstChild;
This works fine in Firefox ESR (10/17/24) and IE9 but fails in IE10, and the reason appears to be because IE10 is inserting weird DOM entries and it's one of those I'm picking up with firstChild instead of the desired thead. I base this on the DOM dump below along with the fact that tableNode.data is set to the string type.
The DOM in IE10 compatibility mode (where it also works) looks like this:
and you can see that the DOM indeed looks sensible. However, examining the DOM in normal IE10 mode shows this:
For what it's worth, Chrome gives me:
and FF17esr gives me:
neither of which seem to have the empty text elements.
Now, I can run the site in compatibility mode but that's an annoying thing to have to tell all our customers. I can also apparently add the hideous:
<meta http-equiv="X-UA-Compatible" content="IE=9">
to my output but I'm not entirely certain what other effects that may have.
I'd like to understand first why IE10 is adding these nodes whereas IE9/FF/IE10compat aren't. There are some discussions I've found stating that whitespace in the HTML may be causing it but it seems to me that this shouldn't result in random nodes being created and, in any case, I don't think I have any superfluous white space. Although I should mention that the value of tableNode.data mentioned above as type string is actually \n, meaning that the newline at the end of the line may be creating this DOM entry.
But, to be honest, that seems ludicrous. HTML is supposed to ignore whitespace outside of tags as far as I'm aware, or at least fold it into a single element. I find it hard to believe that something like:
<tag>line 1</tag>
<tag>line 2</tag>
would result in three DOM entries, tag, empty node and tag just because there's a newline between them.
Any ideas on how to best solve this? Am I going to have to modify my Javascript code to skip these DOM entries?
You can never know where a browser might insert text nodes so you have to make sure you're getting the first child "element"in case the browser put a text node there.
Here's a simple function that will do that:
getFirstChildElement(parent) {
var node = parent.firstChild;
// advance until we get to an element node (skipping text and comment nodes)
while (node && node.nodeType !== 1) {
node = node.nextSibling;
}
return node;
}
Or, if you just want to get the <thead> element, you can simply use this:
table.getElementsByTagName("thead")[0]
Are you absolutely sure Firefox doesn't show those empty text nodes? I'm asking because it should, if it doesn't then it's a bug in Firefox.
Previously only IE behaved the way you expected. All other browsers including Firefox, Chrome, Safari and Opera followed W3C DOM standards which requires them to retain those whitespace. IE10 now join the ranks of other web browsers and behave in a standards compliant way.
You'd be right to complain that this doesn't make sense but it's what the standards require.
As such, the correct way to get the element is to check it's tagName:
var table = document.getElementById("table");
var child = table.firstChild;
while (child && child.tagName != 'thread') {
child = child.nextSibling;
}
// remember to check child after this point because it may be undefined
Additional explanation
Firebug and Chrome's DOM explorer hides those text elements as a matter of convenience, but it's still there. You can try this out:
<html>
<body>
<div id="foo">
<div id="bar">
</div>
</div>
<script>
var f = document.getElementById('foo');
document.body.innerHTML += f.firstChild.id + <br>;
document.body.innerHTML += f.firstChild.nextSibling.id + <br>;
</script>
</body>
</html>
In all browsers except older versions of IE the above page would output:
undefined
bar
That's because the firstChild is the empty text node. You can console.log it if you like to check out that firstChild.
I have the following html
<label>Hello\r\nUsername</label>
<textarea></textarea>
After page load i want to set the content of the label to textarea
normally
$("textarea").val($("label").html()); // or may be $("label").text();
will set the content to the textarea including new lines.It works fine in FF,But not in IE.
It looke like IE is losing the new line info.
How can i solve this ? Please help me.
After a small search on Google I found out that it isn't possible in IE with a version less then 9 since its a built in problem. Check web.student.tuwien.ac.at/~e0226430/innerHtmlQuirk.html for reference. In all, IE<9 removes all white-space in any DOM element except pre and textarea.
This code work greate in any browser (included IE)
document.getElementById('solicit').innerHTML += document.getElementById('prod1').innerHTML+"< br >";
But when I try remove this same substring using IE, it does not work! In Firefox or Chorme works OK.
var text=document.getElementById('solicit').innerHTML;
document.getElementById('solicit').innerHTML = text.replace(document.getElementById('prod1').innerHTML+"< br >","");
IE does not recognize the substring with < br > ?
I tried without < br > tag and IE works correctly, but I need to be able to add and remove spaces in my HTML element.
using Firefox or Chorme it's replaced with no problem.
How to solve this problem?
Thanks a lot!
The innerHTML property doesn't have to return the exact string that you assign to it. Some browsers do, but IE doesn't.
In IE when you read the property, the HTML code is constructed from the elements in the DOM, not from the HTML code that was used to create the elements. In IE you will get back <BR> even if you use <br> in the HTML code to create the element. That could be solved with a case insensetive replace, but the same applies to the elements inside prod1, which might not be as simple to solve depending on what the code looks like.
You should rather add/remove elements in the DOM instead of manipulating HTML. When you use += and replace on the innerHTML property, you will be converting the elements to HTML, then create new elements again, including all the elements in the solicit element that you don't change. You might consider using a library like jQuery, which makes it a lot easier to manipulate elements.
View source and you might see
<BR>
so add a ,"i" to the replace to ignore case - and possibly a regex to handle the missing white space in the result tag
Thanks for all the help!
Knowing the information that you passed me by saying that IE interprets the < br > as < BR > I was only able to develop this solution:
var text=document.getElementById('solicit').innerHTML;
if (navigator.appName=='Microsoft Internet Explorer')
document.getElementById('solicit').innerHTML = text.replace(document.getElementById('prod1').innerHTML+"<BR>","");
else
document.getElementById('solicit').innerHTML = text.replace(document.getElementById('prod1').innerHTML+"<br>","");
With this browse verification my code works correctly. But I'm sure my solution is not the most "elegant" as possible.
Is there any other alternative using only javascript?
Thanks again
problem with IE which removes new lines from $("#content").text()
HTML Code
<div id="content">
<p>hello world</p>
<p>this is a paragraph</p>
</div>
jQuery Code
alert($("#content").text());
result (IE) IE removes new line (\n) how can i fix this problem ?
hello worldthis is a paragraph
result (FF)
hello world
this is a paragraph
take a look :
http://jsfiddle.net/vB3bx/
It works fine if you use the div's innerText property. Try replacing
alert($("#content").text());
with
alert( document.getElementById( "content" ).innerText );
Internet Explorer normalizes all white-space and new-line characters into the SPACE character. As far as I know, there is nothing you can do about it.
btw, it seems that IE9 beta changed this behavior. I get new-lines in it.
I'm pretty sure Sime Vidas is correct. I've tried just about everything and whatever I try (innerText, innerHTML, jQuery methods, TextRange, cloning element and putting it inside a pre element etc etc) white space is removed. I'm guessing IE will just remove it on any type of call. It clearly is there during rendering since a white-space:pre will show it, but retrieving it through javascript will always remove the white space except for pre and textarea content.
This behavior has changed in IE9. The only solution in older versions would be to replace new line characters with tags (or anything really, semicolon etc) on the server if possible and then replace them back into \n in javascript after retrieving the text content.
Not sure you're going to find a solution using text() if you consider the following:
Due to variations in the HTML parsers
in different browsers, the text
returned may vary in newlines and
other white space.
at http://api.jquery.com/text/
I have some JavaScript code that works in IE containing the following:
myElement.innerText = "foo";
However, it seems that the 'innerText' property does not work in Firefox. Is there some Firefox equivalent? Or is there a more generic, cross browser property that can be used?
Update: I wrote a blog post detailing all the differences much better.
Firefox uses W3C standard Node::textContent, but its behavior differs "slightly" from that of MSHTML's proprietary innerText (copied by Opera as well, some time ago, among dozens of other MSHTML features).
First of all, textContent whitespace representation is different from innerText one. Second, and more importantly, textContent includes all of SCRIPT tag contents, whereas innerText doesn't.
Just to make things more entertaining, Opera - besides implementing standard textContent - decided to also add MSHTML's innerText but changed it to act as textContent - i.e. including SCRIPT contents (in fact, textContent and innerText in Opera seem to produce identical results, probably being just aliased to each other).
textContent is part of Node interface, whereas innerText is part of HTMLElement. This, for example, means that you can "retrieve" textContent but not innerText from text nodes:
var el = document.createElement('p');
var textNode = document.createTextNode('x');
el.textContent; // ""
el.innerText; // ""
textNode.textContent; // "x"
textNode.innerText; // undefined
Finally, Safari 2.x also has buggy innerText implementation. In Safari, innerText functions properly only if an element is
neither hidden (via style.display == "none") nor orphaned from the document. Otherwise, innerText results in an empty string.
I was playing with textContent abstraction (to work around these deficiencies), but it turned out to be rather complex.
You best bet is to first define your exact requirements and follow from there. It is often possible to simply strip tags off of innerHTML of an element, rather than deal with all of the possible textContent/innerText deviations.
Another possibility, of course, is to walk the DOM tree and collect text nodes recursively.
Firefox uses the W3C-compliant textContent property.
I'd guess Safari and Opera also support this property.
If you only need to set text content and not retrieve, here's a trivial DOM version you can use on any browser; it doesn't require either the IE innerText extension or the DOM Level 3 Core textContent property.
function setTextContent(element, text) {
while (element.firstChild!==null)
element.removeChild(element.firstChild); // remove all existing content
element.appendChild(document.createTextNode(text));
}
jQuery provides a .text() method that can be used in any browser. For example:
$('#myElement').text("Foo");
As per Prakash K's answer Firefox does not support the innerText property. So you can simply test whether the user agent supports this property and proceed accordingly as below:
function changeText(elem, changeVal) {
if (typeof elem.textContent !== "undefined") {
elem.textContent = changeVal;
} else {
elem.innerText = changeVal;
}
}
A really simple line of Javascript can get the "non-taggy" text in all main browsers...
var myElement = document.getElementById('anyElementId');
var myText = (myElement.innerText || myElement.textContent);
Note that the Element::innerText property will not contain the text which has been hidden by CSS style "display:none" in Google Chrome (as well it will drop the content that has been masked by other CSS technics (including font-size:0, color:transparent, and a few other similar effects that cause the text not to be rendered in any visible way).
Other CSS properties are also considered :
First the "display:" style of inner elements is parsed to determine if it delimits a block content (such as "display:block" which is the default of HTML block elements in the browser's builtin stylesheet, and whose behavior as not been overriden by your own CSS style); if so a newline will be inserted in the value of the innerText property. This won't happen with the textContent property.
The CSS properties that generate inline contents will also be considered : for example the inline element <br \> that generates an inline newline will also generate an newline in the value of innerText.
The "display:inline" style causes no newline either in textContent or innerText.
The "display:table" style generates newlines around the table and between table rows, but"display:table-cell" will generate a tabulation character.
The "position:absolute" property (used with display:block or display:inline, it does not matter) will also cause a line break to be inserted.
Some browsers will also include a single space separation between spans
But Element::textContent will still contain ALL contents of inner text elements independantly of the applied CSS even if they are invisible. And no extra newlines or whitespaces will be generated in textContent, which just ignores all styles and the structure and inline/block or positioned types of inner elements.
A copy/paste operation using mouse selection will discard the hidden text in the plain-text format that is put in the clipboard, so it won't contain everything in the textContent, but only what is within innerText (after whitespace/newline generation as above).
Both properties are then supported in Google Chrome, but their content may then be different. Older browsers still included in innetText everything like what textContent now contains (but their behavior in relation with then generation of whitespaces/newlines was inconsistant).
jQuery will solve these inconsistencies between browsers using the ".text()" method added to the parsed elements it returns via a $() query. Internally, it solves the difficulties by looking into the HTML DOM, working only with the "node" level. So it will return something looking more like the standard textContent.
The caveat is that that this jQuery method will not insert any extra spaces or line breaks that may be visible on screen caused by subelements (like <br />) of the content.
If you design some scripts for accessibility and your stylesheet is parsed for non-aural rendering, such as plugins used to communicate with a Braille reader, this tool should use the textContent if it must include the specific punctuation signs that are added in spans styled with "display:none" and that are typically included in pages (for example for superscripts/subscripts), otherwise the innerText will be very confusive on the Braille reader.
Texts hidden by CSS tricks are now typically ignored by major search engines (that will also parse the CSS of your HTML pages, and will also ignore texts that are not in contrasting colors on the background) using an HTML/CSS parser and the DOM property "innerText" exactly like in modern visual browsers (at least this invisible content will not be indexed so hidden text cannot be used as a trick to force the inclusion of some keywords in the page to check its content) ; but this hidden text will be stil displayed in the result page (if the page was still qualified from the index to be included in results), using the "textContent" property instead of the full HTML to strip the extra styles and scripts.
IF you assign some plain-text in any one of these two properties, this will overwrite the inner markup and styles applied to it (only the assigned element will keep its type, attributes and styles), so both properties will then contain the same content. However, some browsers will now no longer honor the write to innerText, and will only let you overwrite the textContent property (you cannot insert HTML markup when writing to these properties, as HTML special characters will be properly encoded using numeric character references to appear literally, if you then read the innerHTML property after the assignment of innerText or textContent.
myElement.innerText = myElement.textContent = "foo";
Edit (thanks to Mark Amery for the comment below): Only do it this way if you know beyond a reasonable doubt that no code will be relying on checking the existence of these properties, like (for example) jQuery does. But if you are using jQuery, you would probably just use the "text" function and do $('#myElement').text('foo') as some other answers show.
innerText has been added to Firefox and should be available in the FF45 release: https://bugzilla.mozilla.org/show_bug.cgi?id=264412
A draft spec has been written and is expected to be incorporated into the HTML living standard in the future: http://rocallahan.github.io/innerText-spec/, https://github.com/whatwg/html/issues/465
Note that currently the Firefox, Chrome and IE implementations are all incompatible. Going forward, we can probably expect Firefox, Chrome and Edge to converge while old IE remains incompatible.
See also: https://github.com/whatwg/compat/issues/5
This has been my experience with innerText, textContent, innerHTML, and value:
// elem.innerText = changeVal; // works on ie but not on ff or ch
// elem.setAttribute("innerText", changeVal); // works on ie but not ff or ch
// elem.textContent = changeVal; // works on ie but not ff or ch
// elem.setAttribute("textContent", changeVal); // does not work on ie ff or ch
// elem.innerHTML = changeVal; // ie causes error - doesn't work in ff or ch
// elem.setAttribute("innerHTML", changeVal); //ie causes error doesn't work in ff or ch
elem.value = changeVal; // works in ie and ff -- see note 2 on ch
// elem.setAttribute("value", changeVal); // ie works; see note 1 on ff and note 2 on ch
ie = internet explorer, ff = firefox, ch = google chrome.
note 1: ff works until after value is deleted with backspace - see note by Ray Vega above.
note 2: works somewhat in chrome - after update it is unchanged then you click away and click back into the field and the value appears.
The best of the lot is elem.value = changeVal; which I did not comment out above.
As in 2016 from Firefox v45, innerText works on firefox, take a look at its support: http://caniuse.com/#search=innerText
If you want it to work on previous versions of Firefox, you can use textContent, which has better support on Firefox but worse on older IE versions: http://caniuse.com/#search=textContent
What about something like this?
//$elem is the jQuery object passed along.
var $currentText = $elem.context.firstChild.data.toUpperCase();
** I needed to make mine uppercase.
Just reposting from comments under the original post. innerHTML works in all browsers. Thanks stefita.
myElement.innerHTML = "foo";
found this here:
<!--[if lte IE 8]>
<script type="text/javascript">
if (Object.defineProperty && Object.getOwnPropertyDescriptor &&
!Object.getOwnPropertyDescriptor(Element.prototype, "textContent").get)
(function() {
var innerText = Object.getOwnPropertyDescriptor(Element.prototype, "innerText");
Object.defineProperty(Element.prototype, "textContent",
{ // It won't work if you just drop in innerText.get
// and innerText.set or the whole descriptor.
get : function() {
return innerText.get.call(this)
},
set : function(x) {
return innerText.set.call(this, x)
}
}
);
})();
</script>
<![endif]-->
It's also possible to emulate innerText behavior in other browsers:
if (((typeof window.HTMLElement) !== "undefined") && ((typeof HTMLElement.prototype.__defineGetter__) !== "undefined")) {
HTMLElement.prototype.__defineGetter__("innerText", function () {
if (this.textContent) {
return this.textContent;
} else {
var r = this.ownerDocument.createRange();
r.selectNodeContents(this);
return r.toString();
}
});
HTMLElement.prototype.__defineSetter__("innerText", function (str) {
if (this.textContent) {
this.textContent = str;
} else {
this.innerHTML = str.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/\n/g, "<br />\n");
}
});
}