1

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.

1
  • You need to replace innerHTML instead of textContent. Commented May 17, 2021 at 7:33

2 Answers 2

2

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>

Sign up to request clarification or add additional context in comments.

7 Comments

Tk, for your answer, but "div" just is example, it can be everything in origin ( const origin = "abc <div>all is text </div>"; // text input ) If I replace "div" with "<div>" your code will fail.
I don't understand what you mean. I responded to your question as it is, with the example you gave. If you have different cases, then you should edit your question to explicit your possible input/output. It's probably just a matter of changing the regex in there
thank you. I edit for my case, you can check it.
There you've got it
I've refactored the code to optimize it and make it clearer by breaking it into functions. I also changed the way I made the search Regexp global and ignoreCase as it didn't seem to work.
|
0

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>

1 Comment

This is not look like my case, can you check my case, It's hard for me, thank you

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.