-2

I'm trying to retrieve some text from a div with the contentEditable attribute and it's working perfectly fine.

I noticed however that deep cloning the element containing the text would make .innerText completely unusable, as text layout, such as carriage returns or line breaks are apparently gone from the property.

Here is a working example → https://jsfiddle.net/TomWTG/otuakz6q/8/

Here's the related code :

<div contenteditable="true" class="input_text">
  This is a placeholder.
  <div>
    <br />
  </div>
  <div>
    The issue I'm having is that the linebreaks and the carriage returns are
    completely gone from the deep clone's .innerText property.
  </div>
  <div>
    <br />
  </div>
  <div>Try and convert it to see the text layout removed.</div>
</div>

<button>convert</button>
const btn = document.querySelector('button')
const inputText = document.querySelector('.input_text')

btn.addEventListener('click', e => {
  const tempText = inputText.cloneNode(true)
  console.log(tempText.innerText)

  inputText.innerHTML = tempText.innerText
})

As an example, let's say that :

    inputText.value =

    "Hello World, foo bar.

     foo bar."

the expected output coming from tempText.innerText would be :

    "Hello World, foo bar.

     foo bar."

but turns out to be :

    "Hello World, foo bar.foo bar."

so my question is : is there a way I could clone the text and still have access to the both the HTML children and the InnerText at the same time ?

Thanks in advance !

Wenfang Du
  • 8,804
  • 9
  • 59
  • 90
TomWTG
  • 31
  • 1
  • 4
  • Please add a [mcve] – Andreas May 26 '21 at 11:35
  • The `.value` property returns a string, hence there's no `.innerHTML` property (`input.value.innerHTML`) – Andreas May 26 '21 at 11:35
  • that's for javascript, isn't it ? because with vue 3 refs, you have to use ```.value``` to access the DOM element say ```input``` refers to, so ```.InnerHTML```, ```.InnerText``` and ```.TextContent``` do work in this situation – TomWTG May 26 '21 at 11:46
  • There's nothing in your question that indicates the content of `input` which is one reason for my first comment asking for a [mcve] – Andreas May 26 '21 at 11:55
  • I edited the question and added a reproducible example : https://jsfiddle.net/TomWTG/otuakz6q/8/ – TomWTG May 26 '21 at 12:02
  • The fiddle is not the same as the code in this question. And for your problem. Markup (HTML) doesn't care about line-breaks (`\n`) characters. If you want a "line break" then -> `
    `
    – Andreas May 26 '21 at 12:04
  • I'll edit my post in a minute. What I mean is that I could get with the ```.innerText``` property the linebreaks (\n) of the element, but since I need to clone the text not to see the changes directly, ```.innerText``` does not work any longer (on the deep clone). – TomWTG May 26 '21 at 12:08
  • check this, maybe can help you: https://stackoverflow.com/questions/51447846/javascript-clonenode-is-not-a-function – Skatt May 26 '21 at 13:58

1 Answers1

1

As mentioned in the comments basic HTML ignores linebreaks (\n).

Exceptions are the <pre> tag or elements where the CSS property white-space: pre; is set. Text inside of these tags will show your linebreaks.

The reason why you will see formartted text inside your contenteditable <div> is because it actually creates markup while you are editing. Pressing Enter for example will result into an <br> tag and so on.

And because innerText only gives you the text and not the HTML you will not see linebreaks. The problem is not the cloning, it's the same with the uncloned version:

inputText.innerHTML = inputText.innerText;

Result:

"Hello World, foo bar.foo bar."


To solve it you could either use HTML tags that care about text format (<pre> or similar) or you just insert the HTML. Using innerHTML would take care of your linebreaks:

const btn = document.querySelector('button')
const inputText = document.querySelector('.input_text')

  btn.addEventListener('click', (e) =>{
  const tempText = inputText.cloneNode(true)
  console.log(tempText.innerText)

  inputText.innerHTML = tempText.innerHTML
})