Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Interesting conversion of "<br>" between innerHTML and innerText

There are some very simple codes in my project, look like:

const textToHtml = (text) => {
   const div = document.createElement('div');
   div.innerText = text;
   return div.innerHTML;
}

const htmlToText = (html) => {
   const div = document.createElement('div');
   div.innerHTML = html;
   return div.innerText;
}

It has been working normally for the past few months.A few days ago, there was a problem: in some browsers htmlToText('<br>') no more return '\n' as it always, instead it return '', so:

textToHtml(htmlToText('<br>'))
// A few months ago got '<br>'
// but today got '', I lost my '<br>'

In Mac Chrome version:73.0.3683.75 and Mac Firefox version:66.0.3 (64-bit) the '<br>' got lost, but didn't in Mac Safari version: 12.1 (14607.1.40.1.4), other versions and platforms were not tested.

I am sure their version at several month ago worked well, and I know workaround to solve the problem(I can replace all '<br>' to '\n' by RegExp myself), I just wonder has anyone else encountered the same situation? Is this a bug in the browser?

like image 917
fenyiwudian Avatar asked Apr 23 '19 04:04

fenyiwudian


People also ask

What is difference between innerHTML and innerText?

innerText returns all text contained by an element and all its child elements. innerHtml returns all text, including html tags, that is contained by an element.

What can I use instead of innerText?

In addition to innerText not working in Firefox: textContent seems to work in all major browsers, so just use textContent instead of innerText.

Why is writing to the textContent property superior to innerHTML?

textContent = 'Show Filter'; This will also achieve the same result but it doesn't have security issues like innerHTML as it doesn't parse HTML like innerText. Besides, it is also light due to which performance increases. So if a text has to be added like above, then its better to use textContent.


Video Answer


2 Answers

There is an example on the MDN documentation that compares innerText and textContent and where explicitly says:

This example compares innerText with Node.textContent. Note how innerText is aware of things like <br> tags, and ignores hidden elements.

So, I have tested this on Firefox 66.0.3 (64bits) and it still work if the element from/where you are setting/getting the properties is rendered or exists on the document.body while you perform the operations. You can check the next two examples:

Example 1: The div element already exists on the document.body

const textToHtml = (text) => {
   const div = document.getElementById('test');
   div.innerText = text;
   return div.innerHTML;
}

const htmlToText = (html) => {
   const div = document.getElementById("test");
   div.innerHTML = html;
   console.log("Note <br> is parsed to \\n =>", div.innerText);
   return div.innerText;
}

console.log("Output =>", textToHtml(htmlToText(`Some<br>Other`)));
.as-console {background-color:black !important; color:lime;}
<div id="test"></div>

Example 2: The div element is appended dynamically on the document.body

const textToHtml = (text) => {
   const div = document.createElement('div');
   document.body.append(div);
   div.innerText = text;
   return div.innerHTML;
}

const htmlToText = (html) => {
   const div = document.createElement('div');
   document.body.append(div);
   div.innerHTML = html;
   console.log("Note <br> is parsed to \\n =>", div.innerText);
   return div.innerText;
}

console.log("Output =>", textToHtml(htmlToText(`Some<br>Other`)));
.as-console {background-color:black !important; color:lime;}

And, like you say, it won't work (on some newer browsers) if the element don't exists on the document, however I don't know exactly what is the reason about it (maybe it is because the element you create is not rendered):

Example 3: The div element is not present on the document.body

const textToHtml = (text) => {
   const div = document.createElement('div');
   div.innerText = text;
   return div.innerHTML;
}

const htmlToText = (html) => {
   const div = document.createElement('div');
   div.innerHTML = html;
   console.log("Note <br> isn't parsed to \\n =>", div.innerText);
   return div.innerText;
}

console.log("Output =>", textToHtml(htmlToText(`Some<br>Other`)));
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

Anyway, I have come to the next approach that creates a div element, appends it to the body and then removes it. This way, you won't have any visual perturbation and should work nicely for all browsers:

New Implementation:

const textToHtml = (text) => {
   const div = document.createElement('div');
   document.body.append(div);
   div.innerText = text;
   const html = div.innerHTML;
   div.remove();
   return html;
}

const htmlToText = (html) => {
   const div = document.createElement('div');
   document.body.append(div);
   div.innerHTML = html;
   const text = div.innerText;
   div.remove();
   return text;
}

console.log("Output =>", textToHtml(htmlToText(`Some<br>Other`)));
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}

Extra: There is a good read about innerText on the-poor-misunderstood-innerText

like image 93
Shidersz Avatar answered Nov 15 '22 08:11

Shidersz


Works as specified in https://html.spec.whatwg.org/multipage/dom.html#the-innertext-idl-attribute

Can be set, to replace the element's children with the given value, but with line breaks converted to br elements.

Why it differs if it is rendered was not clear to me, thats why I by favor, do not rely on this behaviour.

I have no example of methods that pass a the inverse-test like this:

assert textToHtml(htmlToText(x)) === x;
like image 34
Grim Avatar answered Nov 15 '22 07:11

Grim