6

So I am having trouble implementing this scenario:

From the backend server, I am receving an html string, something along like this:

<ul><li><strong>Title1</strong> <br/> <a class=\"title1" href="title1-link">Title 1</a></li><li><strong>Title2</strong> <a class="title2" href="/title2-link">Title 2</a>

Normally, that would be fine when just using dangerouslySetInnerHTML.

However, around the a href tags in the html, I need to wrap those in component like so:

<ModalLink href={'title'}>
    {Title}
</ModalLink>

This is because when wrapping the a tags, the component essentially adds functionality on creating a new child window.

I figured this is something you would need to implement on Regex, but I dont have the slightest idea where to begin.

Alejandro
  • 2,266
  • 6
  • 35
  • 63

2 Answers2

2

You can deconstruct and extract the necessary values from your html string with regex and then use JSX instead of dangerouslySetInnerHtml. This component shows how to render your sample html string.

import React, { Component } from 'react'

export default class App extends Component {
    render() {
        const html = `<ul><li><strong>Title1</strong><br/><a class="title1" href="/title1-link">Title 1</a></li><li><strong>Title2</strong><br/><a class="title2" href="/title2-link">Title 2</a></li></ul>`

        return (
            <div>
                <ul>
                {html.match(/(<li>.*?<\/li>)/g).map( li => {
                    const title =  li.match(/<strong>(.*?)<\/strong>/)[1]
                    const aTag = li.match(/<a.*?\/a>/)[0]
                    const aClass = aTag.match(/class="(.*?)"/)[1]
                    const href = aTag.match(/href="(.*?)"/)[1]
                    const aText = aTag.match(/>(.*?)</)[1]
                    return (
                        <li>
                            <strong>{title}</strong>
                            <br/>
                            <a className={aClass} href={href}>{aText}</a>
                        </li>
                    )
                })}
                </ul>
            </div>
        )
    }
}

From there you can simply wrap the a tag in your ModalLink component. I'm not sure this is exactly how you want to do that, but here is an example.

return ( 
    <li>
        <strong>{title}</strong>
        <br/>
        <ModalLink href={href}>
            <a className={aClass} href={href}>{aText}</a>
        </ModalLink>
    </li>
)

html.match(/(<li>.*?<\/li>)/g) matches each <li>...</li> within the html string in an array, which can then be mapped. Then I extract the title, href, etc. out of each <li>...</li> using captures (the part within parentheses), which can then be used in JSX. This answer provides more detail on the regular expressions used.

lemarc
  • 111
  • 1
  • 3
1

Unfortunately I've never really used JavaScript which is why my answer will focus solely on the regex part of this question. (I've added an attempt a the bottom, though!)

If I understand it correctly you want to replace the <a href="someLink">someTitle</a> tags with a <ModalLink href={'someLink'}>someTitle</ModalLink> in a way that the someLink and someTitle will be in the ModalLink tag, too - please do correct me if I'm understanding this in a wrong way

Now look at this regex pattern here

<a [^<]+?href\s*=\s*("|')(.*?)\1>(.*?)<\/a>

it will match with any tag starting with <a and matches all characters until it finds an href (with any number of whitespaces between the href and the equation mark). Then it will search for a string between either '' or "" quotation marks and capture it in order to be used later on. It again matches until it finds the end of the tag > and captures whatever is between that end and the closing tag <\a>.

If you now use some method for replacing the matched regex in the given string (I'm sorry that I'm unfamiliar with how this would work in JavaScript) and replace it with this pattern

<ModalLink href={'$2'}> {$3} </ModalLink>

You will get a result like this for the example html string you're receiving:

<ul><li><strong>Title1</strong> <br/> <ModalLink href={'title1-link'}> {Title 1} </ModalLink></li><li><strong>Title2</strong> <ModalLink href={'/title2-link'}> {Title 2} </ModalLink>

The $2 and $3 part of the replacing pattern are placeholders for the before mentioned captured parts which will just be replaced with them as you can see. (They are capturing group 2 and 3 instead of starting with 1 simply because I've captured the quotation marks as capturing group 1 already)

You can try the pattern I've provided here.

While you can see and edit the regex and the string input on the upper part of the window, the replace pattern and its result can be found in the lower part.


EDIT: I've now tried my best with an online compiler to use JavaScript methods for replacing the tags with the tags and it seems to just work fine when using this method with the above mentioned regex:

var regexMatch = html.replace(/<a [^<>]+?href\s*=\s*("|')(.*?)\1[^<>]*?>(.*?)<\/a>/g, "<ModalLink href={'$2'}> {$3} </ModalLink>");

In this case the html should of course be the html string in which you want to replace the <a> tags.

You can also try this online here.

Tornadowarnung
  • 368
  • 3
  • 11