I am updating my application and I have decided to use bootstrap 5 which no longer has the jquery dependency and to eliminate this dependence from my application as well.
So I'm rewriting the javscript part from jquery to js vanilla.
I use AJAX a lot to load content in different divs and for their subsequent manipulation based on certain events triggered by the user. Unfortunately, in some cases I find myself forced to hang a script tag together with the html part to run a javascript function that I cannot execute in any other way.
For example:
<script>myFuncrion(val1, val2, val3);</script>
<div id="myDiv">
<div>Other html code ..</div>
</div>
With jquery something like this was enough to append the markup to a given div and execute the javascipt function
$('#elementToAppend').append(html);
Converting this to vanilla js I get something like this
document.getElementById('elementToAppend').innerHTML = html;
Everything is correctly appended, but obviously the js is not executed
I don't know jquery behind the scenes, but I assume it is being manipulated in some way for the javascript part to run.
I then created a function that would get everything back to working
const functionOne = (elem) => {
// I make the AJAX call...
let jsAndData = getJsAndData(data);
// Append the html string
document.querySelector(elem).innerHTML = jsAndData.cleanData;
// I run the js
eval(jsAndData.js);
}
const getJsAndData = data => {
var js = "";
// Check if there is a <script> tag
let script = data.match(/<script>(.*?)<\/script>/g);
// If there is a script tag I extrapolate the js content
if (script) {
script.map(val => {
js = val.replace(/<\/?script>/g, "");
});
// I remove the <script> tag and its content from the html string
let cleanData = data.replace(/<script[^>]*>.*<\/script>/gm, "");
return { cleanData: cleanData, js: js };
} else {
return { cleanData: data, js: js };
}
};
In this way I get the same result I had with jquery, even better, because on the DOM there is no longer any trace of the script tag
Now, my questions are:
Your way is a correct way. For security reasons (XSS) the script tag is not run when using innerHTML.
https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#security_considerations
Alternative: In MDN you can find hacky code like this to work around from the backend without touching the frontend. I would not recommend this way.
const name = "<img src='x' onerror='alert(1)'>";
el.innerHTML = name; // shows the alert