Phát Nguyễn
Phát Nguyễn

Reputation: 175

Replace text with custom html

I want to display text message conversations in my chat app.

My case: When user search some text in search box, message include searchText will be style with red color. Example:

user search: "div"

// messageText = "abc <div>all is text</div>" (searching in plain text here);
// htmlText = "abc &lt;div&gt;all is text&lt;/div&gt;";
// OUTPUT MUST BE: "abc &lt;<span style='color: red'>custom</span>&gt;string &lt;<span style='color: red'>custom</span>&gt"

Here is my code:

const origin = "abc <div>all is text </div>"; // text input
const str = "abc &lt;div&gt;all is text &lt;/div&gt;"; // after sanitize

const element = document.createElement("div");
element.innerHTML = str;
for (let node of element.childNodes) {
  // I want replace "div" text with my custom html
  node.textContent = node.textContent.replace(/div/gi, "<span style='color: red'>custom</span>");
}

const result = element.innerHTML;
console.log(result);

Here is the result output

Output

abc &lt;&lt;span style='color: red'&gt;custom&lt;/span&gt;&gt;string &lt;/&lt;span style='color: red'&gt;custom&lt;/span&gt;&gt;

Expect

abc &lt;<span style='color: red'>custom</span>&gt;string &lt;<span style='color: red'>custom</span>&gt;

Can you help me, tks for your help.

Upvotes: 1

Views: 1296

Answers (2)

julien.giband
julien.giband

Reputation: 2644

node.textContent = ... will produce valid text, by escaping whatever you pass to it.

If you want to insert HTML instead, use node.innerHTML

node.innerHTML = node.textContent.replace(/div/gi, "<span style='color: red'>custom</span>");

Edit I realize your problem is more complex than that. You first need to escape HTML inside your text, and then replace div with the HTML you want to insert, and finally use inneHTML to apply the result.

Edit2 After updating your question, I understand you want to search/highlight something within text input. Edited the code to do that

As per this answer:

function escapeHtml(unsafe) {
  return unsafe
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");
}

function highlightSearch(node, query) {
  //Within node, highlight matched text (using replacement "$&")
  //highlight done by surrounding found text with a <span>
  let txt = node.textContent;                 //Get inner text
  console.log('raw text:', txt);
  txt = escapeHtml(txt);                      //Escape text with HTML entities
  console.log('html text:', txt);
  //Search and replace ("$&" = whole matched substring)
  txt = txt.replaceAll(query, "<span style='color: red'>$&</span>");
  console.log('highlighted:', txt);
  //Show result
  node.innerHTML = txt;         //<-- innerHTML
}

document.querySelector('#btn-search').addEventListener('click', e => {
  //Read query
  let q = document.querySelector('#search-query').value;
  console.log('raw query:', q);
  //Make search query html
  q = escapeHtml(q);
  console.log('html query:', q);
  //Perform search/highlight
  document.querySelectorAll('.search-in').forEach(node => {
    highlightSearch(node, q);
  });
});
button {
  margin-top: 1em;
}
<p class="search-in">abc &lt;div&gt;all is text &lt;/div&gt;</p>
<p class="search-in">a &lt;div> is not a &lt;/div>. but I can find 2 &lt;div></p>
<input type="search" id="search-query" value="<div>" />
<button id="btn-search">Search</button>

Upvotes: 2

KooiInc
KooiInc

Reputation: 122986

Maybe you don't need to sanitize:

const origin = document.querySelector("#inp").value;
const tmp = Object.assign( document.createElement("div"), {innerHTML: origin} );
tmp.querySelectorAll("div").forEach( el => {
  const left = `<span style="color:red">&lt;custom&gt;</span>`;
  const right = `<span style="color:red">&lt;/custom&gt;</span>`;
  const nwSpan = Object.assign( 
    document.createElement("span"),
    {innerHTML: `${left}${el.innerHTML}${right}`} );
  el.parentNode.replaceChild(nwSpan, el);
} );
console.log(tmp.innerHTML);
document.querySelector("#result").innerHTML = tmp.innerHTML;
<input type="text" id="inp" value="abc <div>all is text </div>">

<pre id="result"></pre>

Upvotes: 0

Related Questions