Alternative for innerHTML?
Asked Answered
J

13

54

EDIT: WOW. This question is 12 years old now.

As someone stated, it can be done with a one-liner since 2016: https://mcmap.net/q/335761/-alternative-for-innerhtml


The original:

I'm wondering if there's a way to change the text of anything in HTML without using innerHTML.

Reason I'm asking is because it's kinda frowned upon by the W3C. I know it's nitpicking, but I just wanna know, is there a way?

EDIT: people seem to misunderstand what I'm asking here: I want to find a way to effectivly change the text being displayed.

If I have:

<div id="one">One</a>

innerHTML allows me to do this:

var text = document.getElementsById("one");
text.innerHTML = "Two";

And the text on my screen will have changed.
I do not wish to append more text, I wish to change allready existing text.

Joanjoana answered 5/4, 2009 at 0:9 Comment(5)
FYI: innerHTML is extremly faster compared to use DOM createElement, createTextNode, etc. Efficency consideration: quirksmode.org/dom/innerhtml.html Moreover innerHTML is part of HTML5!Haberdasher
@Marco what do you mean when you say innerHTML is part of HTML5?Chapfallen
@Pacerier: innerHTML works in all browsers, but it is not part of the W3C HTML4.1 standards (and WebDevHobo says to be frowned upon this). Whilest innerHTML is supposed to be part of the HTML5: w3.org/TR/2011/WD-html5-diff-20110113/#htmldocument-extensionsHaberdasher
Maybe because it's .innerHTML and not .innerHtml, Javascript (unlike PHP) is a case sensitive language.Haberdasher
@Chechulin ericvasilik.com/2006/07/code-karma.html (TL;DR: when they invented innerHTML, they couldn't make it work on tables, so they made it read-only on tables. This was fixed only in IE9. Article is by the inventor of innerHTML.)Brink
R
48

The recommended way is through DOM manipulation, but it can be quite verbose. For example:

// <p>Hello, <b>World</b>!</p>
var para = document.createElement('p');
para.appendChild(document.createTextNode('Hello, '));

// <b>
var b = document.createElement('b');
b.appendChild(document.createTextNode('World');
para.appendChild(b);

para.appendChild(document.createTextNode('!'));

// Do something with the para element, add it to the document, etc.

EDIT

In response to your edit, in order to replace the current content, you simply remove the existing content, then use the code above to fill in new content. For example:

var someDiv = document.getElementById('someID');
var children = someDiv.childNodes;
for(var i = 0; i < children.length; i++)
    someDiv.removeChild(children[i]);

But as someone else said, I'd recommend using something like jQuery instead, as not all browsers fully support DOM, and those that do have quirks which are dealt with internally by JavaScript libraries. For example, jQuery looks something like this:

$('#someID').html("<p>Hello, <b>World</b>!</p>");
Relinquish answered 5/4, 2009 at 0:20 Comment(5)
so actually, first place new text and then remove old... that seems a very lenghty way to do things... I wonder why the W3C does not approve of innerHTMLJoanjoana
Other way around :) Their view is that with innerHTML, it's possible to insert invalid markup into an XML/XHTML document. Though that said, they seem to have changed their minds with HTML5.Relinquish
jQuery uses innerHTML many times inside code, therfor suggesting to use jQuery in order avoid using innerHTML does not make much sense IMHO.Haberdasher
Also, you should properly check your "not all browsers fully support DOM" statement in the context of this question. It's true that some browsers (mainly IE) have poor support of DOM, but, for this subject, methods are fully supported. Check compatibility tables: quirksmode.org/dom/w3c_core.html#creatingelements quirksmode.org/dom/w3c_core.html#t90Microlith
A nicer way to remove all the childnodes would be while (el.firstChild) { el.removeChild(el.firstChild); } Looks cleaner and no need for an extra indexed loopVanquish
A
14

The better way of doing it is to use document.createTextNode. One of the main reasons for using this function instead of innerHTML is that all HTML character escaping will be taken care of for you whereas you would have to escape your string yourself if you were simply setting innerHTML.

Authorize answered 5/4, 2009 at 0:17 Comment(2)
However, it seems that innerHTML is much faster than the W3C DOM methods: quirksmode.org/dom/innerhtml.html.Castalia
It depends what you're doing; it's misleading to say one method is blanket better. DOM tends to slow when doing childNode list operations on lots of elements (tending to O(n²)), where innerHTML can do them all at once. But innerHTML's parsing/serialisation step can make other operations slower.Holder
M
10

You can get the same effect by manipulating the DOM. The safest way to change text is to remove all the child nodes of the element and replace them with a new text node.

var node = document.getElementById("one");

while( node.firstChild )
    node.removeChild( node.firstChild );
node.appendChild( document.createTextNode("Two") );

Removing the child nodes gets rid of the text content of your element before replacing it with the new text.

The reason most developers avoid using innerHTML is that accessing elements through the DOM is standards compliant.

Moonmoonbeam answered 5/4, 2009 at 3:30 Comment(0)
P
7

If you only want to change plain text, then there's a quicker solution that relies on standards:

document.getElementById("one").firstChild.data = "two";

Anyway, please note that innerHTML is going to be part of the upcoming HTML 5 standard.

Plumbic answered 5/4, 2009 at 17:25 Comment(0)
Q
6

Simple.

Replace text.innerHTML = 'two' with text.firstChild.nodeValue = 'two'.

Quietly answered 28/11, 2010 at 12:7 Comment(0)
N
6

Also looking for a good alternative to bypass element.innerHTML I finally found that solution:

HTMLElement.prototype.htmlContent = function(html)
{
    var dom = new DOMParser().parseFromString('<template>'+html+'</template>', 'text/html').head;
    this.appendChild(dom.firstElementChild.content);
}

//-- document.getElementById('my-id').innerHTML = string_of_html;
document.getElementById('my-id').htmlContent(string_of_html);

Another alternative without <template> tags, but loop instead:

HTMLElement.prototype.htmlContent = function(html)
{
    var dom = new DOMParser().parseFromString(html, 'text/html').body;
    while (dom.hasChildNodes()) this.appendChild(dom.firstChild);
}

Keep in mind that this method actually 'add' content when innerHTML 'replace' content...

This may help:

HTMLElement.prototype.clearContent = function()
{
    while (this.hasChildNodes()) this.removeChild(this.lastChild);
}

//-- document.getElementById('my-id').innerHTML = '';
document.getElementById('my-id').clearContent();

doc: https://github.com/swannty/escaping-innerHTML
perf: https://jsperf.com/escaping-innerhtml

Noggin answered 7/3, 2017 at 21:18 Comment(0)
H
6

This is a very old question.

Now, things changed:

element.innerText = "Hi There!"

A one-liner. Since 2016 every single browser supports this.

Heist answered 25/9, 2021 at 1:38 Comment(1)
It's helpful to use when you want the content of div or p as string and not as escaped html string.Hubblebubble
G
3
var who=document.getElementById('one'), txt='new text';
if(who.innerText) who.innerText=txt;
else if(who.textContent) who.textContent= txt;

This may be as objectionable as innerHTML to you, but it has the advantage of working in some cases (IE) where innerHTML or appendChild do not, like some table nodes, the text of style and script elements and the value of form fields

Garofalo answered 6/4, 2009 at 14:8 Comment(0)
M
1

You could use DOM as follows:

<html>
<body>
<div>before</div>
<script type="text/javascript">
var element = document.getElementsByTagName("div")[0];
alert(element.firstChild.nodeValue);
element.removeChild(element.firstChild);
element.appendChild(document.createTextNode('after'));
alert(element.firstChild.nodeValue);
</script>
</body>

But I think anyone rarely do this but use a framework like jQuery or Prototype or any other javascript framework out there instead. This is jquery example:

<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
</head>
<body>
<div>before</div>
<script type="text/javascript">
var element = $("div");
alert(element.text());
element.text("after");
alert(element.text());
</script>
</body>
Motif answered 5/4, 2009 at 0:23 Comment(0)
H
1

It appears to me that the CSS+HTML+JS combination should achieve desired effects:

.myelement:before {   
    content: attr(alt);
} 

...

<span class='myelement' alt='initial value'></span> 

...

element.setAttribute('alt', 'new value'); 

Does anyone know if this works in practice?

Haemolysis answered 16/6, 2009 at 10:2 Comment(0)
H
1

Well i f i understand your question properly this should be an answer.

var text = document.getElementById("one");
//text.innerHTML = "Two";
 text.childNodes[0].nodeValue="two";
Harem answered 24/9, 2011 at 7:54 Comment(0)
C
1

insertAdjacentHTML() is the way to go. Read more: Click for documentation

Celebrant answered 8/2, 2019 at 19:55 Comment(2)
While this link may answer the question, it is better to include a usable code example here and provide the link for reference.Koheleth
insertAdjacentHTML has the same security concerns as innerHTML and is a potential XSS vector.Picturize
C
0

I sometimes find it helpful to store a direct reference to the text node if I am going to be updating it regularly. I do something like this:

var dynamicText = myDiv.appendChild(document.createTextNode("the initial text"));

And then whenever I need to update it, I just do this:

dynamicText.nodeValue = "the updated text";

This prevents having to walk the DOM or add or remove any children.

Cene answered 10/10, 2013 at 13:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.