Reputation: 379
I am using React and Javascript and have a requirement where I need to extract certain anchor tags, take their attributes like id, href and create a custom React link component out of it.
My string looks like this
"<p>Bla bla bla bla.</p>\n<ul>\n<li><strong>Bla bla</strong>. Bla bla bla.</li>\n<li><strong>Bla bla bla</strong>.<a href='#footnote1' id='sup1'><sup>1</sup></a> Bla bla bla.</li>\n<li><strong>Bla bla bla.<a href='#footnote2' id='sup2'><sup>2</sup></a>\r\n</strong>  Bla bla bla.</li>\n<li><strong>Bla bla:</strong>Bla bla <a href=\"https://google.com\" target=\"no\">Google</a> * bla bla bla.<a href='#footnote1' id='sup3'><sup>1</sup></a></li>\n</ul>\n<p> </p>"
I want to only extract all those <a>
that have <sup>
inside them. I want to then take the attributes of such <a>
and create a custom React link component like
<MyLink
id={id of the anchor tag}
addClasses={"footnote-link"}
href={href of anchor tag}
handleClick={myClickHandler}
ariaProps={{
label: {text inside the sup tag}
}}
>
<sup className={href of anchor tag !== null ? "custom-class" : ""}>{text inside the sup tag}</sup>
</MyLink>
I then want to replace those <a>
with my custom component in the string. Reason I am trying to convert <a>
to custom component is that I want the new anchor tag to be A11Y compliant and anchor tags and the source string are not in my control.
I tried the combination of How to get the href value of an anchor tag with javascript from a string and javascript regex to extract anchor text and URL from anchor tags, but couldn't make much progress. I also tried react-string-replace, but that didn't help much either.
I also have an option of getting <a href='#footnote1' id='sup1'><sup>1</sup></a>
replaced with something like #FootNote({id:\"sup1-CB\", goto:\"sup1\", data:\"1\"})#FootNote
and then use "id", "goto" and "data" to create the custom link.
Can anyone provide some guidance on how to achieve this? I apologize for the long question.
Upvotes: 0
Views: 2831
Reputation: 27265
You might consider parsing the HTML and modifying it using DOM methods, then rendering it back out as a string. The demo below is just a proof of concept, but it could be incorporated into a React component that does the same sort of thing.
Note: This is similar to Dean's answer which has a more React-specific (and arguably cleaner) example.
const input = "<p>Bla bla bla bla.</p>\n<ul>\n<li><strong>Bla bla</strong>. Bla bla bla.</li>\n<li><strong>Bla bla bla</strong>.<a href='#footnote1' id='sup1'><sup>1</sup></a> Bla bla bla.</li>\n<li><strong>Bla bla bla.<a href='#footnote2' id='sup2'><sup>2</sup></a>\r\n</strong>  Bla bla bla.</li>\n<li><strong>Bla bla:</strong>Bla bla <a href=\"https://google.com\" target=\"no\">Google</a> * bla bla bla.<a href='#footnote1' id='sup3'><sup>1</sup></a></li>\n</ul>\n<p> </p>"
const parser = new DOMParser();
const doc = parser.parseFromString(input, 'text/html');
// might be a more efficient way to do this. just querying for anchors
// and filtering out the ones that don't have a <sup> child
const anchors = [...doc.querySelectorAll('a')].filter(elem => elem.querySelector('sup'));
anchors.forEach(a => {
const sup = a.querySelector('sup');
a.setAttribute('aria-label', sup.innerText);
// etc.
})
document.getElementById('demo').innerHTML = doc.body.innerHTML;
document.getElementById('source').innerText = doc.body.innerHTML;
<h2>Resulting html</h2>
<pre id="source"></pre>
<hr/>
<h2>Rendered result</h2>
<div id="demo"></div>
Upvotes: 0
Reputation: 2623
Here's an example that uses a created tag to parse your html, then use DOM methods to extract the data you need:
const str =
"<p>Bla bla bla bla.</p>\n<ul>\n<li><strong>Bla bla</strong>. Bla bla bla.</li>\n<li><strong>Bla bla bla</strong>.<a href='#footnote1' id='sup1'><sup>1</sup></a> Bla bla bla.</li>\n<li><strong>Bla bla bla.<a href='#footnote2' id='sup2'><sup>2</sup></a>\r\n</strong>  Bla bla bla.</li>\n<li><strong>Bla bla:</strong>Bla bla <a href=\"https://google.com\" target=\"no\">Google</a> * bla bla bla.<a href='#footnote1' id='sup3'><sup>1</sup></a></li>\n</ul>\n<p> </p>";
const el = document.createElement("html");
el.innerHTML = str;
const anchors = el.getElementsByTagName("a");
const MyLink = () => null;
const myClickHandler = () => null;
export default () =>
[...anchors].map((anchor, index) => {
const sup = anchor.getElementsByTagName("sup");
if (sup.length === 0) {
return null;
}
return (
<MyLink
key={index.toString()}
id={anchor.id}
addClasses={"footnote-link"}
href={anchor.href}
handleClick={myClickHandler}
ariaProps={{
label: sup[0].innerHTML
}}
>
<sup className={anchor.href ? "custom-class" : ""}>{sup[0].innerHTML}</sup>
</MyLink>
);
});
Replace MyLink
and myClickHandler
with your own.
Upvotes: 1