I have an XML string which is displayed in a span in a pre tag:
<pre className="xmlContainer">
<span id="xml-span"></span>
</pre>
The XML looks something like this:
<root>
<child-to-replace>
<child-to-replace/>
...
<root/>
With multiple (unknown) number of the child-to-replace tag.
I replace < and > to display the xml which is contained in a variable xml:
let element = document.getElementById('xml-span');
var displayXml = xml.replaceAll('<','<').replaceAll('>','>');
element.innerHTML = displayXml;
I also want to replace all instances of the opening tag of child-to-replace with an anchor tag which calls a function updateParentScope. I have tried to simply replace it:
function updateParentScope(scope) {
//updates scope for parent
}
useEffect(() => {
let element = document.getElementById('xml-new');
var displayXml = xml.replaceAll('<','<').replaceAll('>','>')
.replaceAll('child-to-replace',
'<a onclick="updateParentScope(\"sometext\")" >child-to-replace</a>')
element.innerHTML = displayXml;)
element.innerHTML = replaced;
}, [xml])
This gives Uncaught ReferenceError: updateParentScope is not defined when clicked.
Is there a way to solve this or is replacing the text the wrong approach?
The solution I found was to change the anchor tag to a button, then get the element from the DOM after render with a useEffect hook. When the element is retrieved, add an event listener.
useEffect(() => {
const cond = document.getElementById(btnId) || false;
if (cond && !hasEventListener){
var btn = document.getElementById(btnId);
btn.addEventListener('click', updateParentScope)
setHasEventListener(true);
}
setHasEventListener(false);
})
The cond check is to make sure the element is rendered in the DOM.
I needed to add hasEventListener to state in order to not add the event listener multiple times:
const [hasEventListener, setHasEventListener] = useState(false);
This is not an ideal solution as the function called by the click event does not accept parameters.