0

I am not sure if this is possible or not but I am receiving an element from the backend and I am trying to modify it to convert a word to a link. This is all in Vue3/Typescript.

Example of backend data I can receive:

<p class="random-class">
  Foo bar bash is zoo monster <span class="different-class">poop zebra</span>
</p>

Attempt Let's say that I am trying to convert all words that start with z to an href

const convertWordToHashtag = (element: BackendDataSample) => {
  // extracts the text portion of the content to an array of words
  const textArray = element.textContent.split(' ');
  // checks if anything starts with z
  textArray.forEach((word: string) => {
    if (word && word.charAt(0) === 'z') {
      let newElement = document.createElement('a');
      newElement.href = `https://www.google.com/${word}`;
      newElement.textContent = word;
      
      // go back to the original element 
      element.textContent.replace(word, newElement);
    }
  });
}

My goal is to essentially transform the Element to be used so that it will read:

<p class="random-class">
  Foo bar bash is <a href="https://www.google.com/zoo">zoo</a> monster <span class="different-class">poop <a href="https://www.google.com/zebra">zebra</a></span>
</p>

But this doesn't seem to work the replace errors out. Is this the right approach or is there an easier way to do this?

8
  • You can do it via the DOM by finding text nodes and breaking them into two for each new element. Or, you can look at the HTML for the block of the page you want to affect and operate on that (as HTML code) that you can then use to update .innerHTML as necessary. Commented Jul 22 at 15:11
  • The textArray.forEach is missing a closing ) Commented Jul 22 at 15:16
  • 1
    That said, please include a minimal reproducible example. Withtout eg the ` createHrefUrl` it's hard to debug your issue Commented Jul 22 at 15:17
  • 1
    Unless you already have attached event handlers to some elements in this input HTML, the easiest is to use re-assign the altered HTML using only string manipulation, and not create DOM elements with createElement. Is there a reason you prefer to manipulate the DOM with createElement? Commented Jul 22 at 16:01
  • 2
    Side note: there is nothing in your question that depends on vuejs. The tag is not really relevant. Commented Jul 22 at 16:02

2 Answers 2

1

You cannot insert HTML elements by assigning to the textContent property, not to mention that replace returns the result -- strings are not updated in-place; they are immutable. To assign structured content you'd have to assign to the innerHTML property. For very simple, predictable HTML that would be the best option. On the other hand, in general HTML can get complex, and your "z" words might be part of HTML attributes, HTML comments, <script> contents, etc. So with that in mind, I would suggest using a tree walker.

Here is how that could look in plain JavaScript:

function* iterateTextNodes(root) {
    const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT);
    while (walker.nextNode()) yield walker.currentNode;
}

const convertWordToHashtag = (element) => {
    for (const node of Array.from(iterateTextNodes(element))) {
        const matches = node.textContent.split(/(\bz\S+)/g);
        if (matches.length === 1) continue;
        node.replaceWith(...matches.map((s, i) => {
            if (i % 2 === 0) return s; // Text between matches
            const a = document.createElement("a");
            a.href = `https://www.google.com/${s}`;
            a.textContent = s;
            return a;
        }));
    }
}

// demo
const element = document.querySelector("p");
convertWordToHashtag(element);
console.log(element.innerHTML); // Verify the resulting HTML
<p class="random-class">
  Foo bar bash is zoo monster <span class="different-class">poop zebra</span>
</p>

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

Comments

-2

The problem comes in when you try using textArray.innerHTML=foo. This will take the href link and add it as a string in the random-class text content. Otherwise the DOM is manipulated.

1 Comment

textArray does not have an innerHTML property. Nor is it true that assigning to the innerHTML property of a DOM element would add the href link as a string. innerHTML does understand and parse the HTML format, hence the name of that property.

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.