0

I have a JavaScript function that gets data and a function statement from PHP via XMLHttpRequest.How do I call the function that the PHP returned? It doesn't seem to exist. I'm totally lost as to how to make this happen. Here are test files that better explain it:

test.html

<!DOCTYPE html>
<html lang="en">
<head>
<script>
function main(){
    var xhttp = new XMLHttpRequest();
    xhttp.open("POST", "/test2.php", true);
    xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    xhttp.send('foo=bar');
    xhttp.onreadystatechange = function(){
        if (xhttp.readyState == 4 && xhttp.status == 200) {
            document.getElementById('testDiv').innerHTML = xhttp.responseText;
            if (typeof injectedJS === "function") {
                console.log('yes');
            }else{
                console.log("no");
            }
        }
    };
};
</script>
</head>
<body onLoad=main()>
<div id="testDiv"></div>
</body>
</html>

test2.php

<?php
echo("<h1>Hello!</h1>");
echo("<script>function injectedJS() {var foo='bar';}</script>");
?>

The "Hello!" text is being displayed but "no" is logged to the console.

Thanks in advance for any help or a steer in the right direction, John

John
  • 3
  • 2
  • 1
    How do you expect that `injectedJS` would be assigned a value? – Pointy Jun 21 '22 at 21:38
  • A steer in the right direction would be to `eval(xhttp.responseText)` into life. – IT goldman Jun 21 '22 at 21:42
  • @ITgoldman - if it were 2014, sure. – Bravo Jun 21 '22 at 23:32
  • script tags injected via ajax (or maybe even through innerHTML?) are not executed ... what you do is find the "injected" script tags, create a new script tag and copy the content into it – Bravo Jun 21 '22 at 23:34
  • @Pointy - OP exepcts the added html `` would declare `function injectedJS` – Bravo Jun 21 '22 at 23:35
  • You really should change your whole approach to this. Don't try to execute code from the server. Return structured data (e.g. JSON) and process the various bits of it). – Quentin Jun 22 '22 at 00:08
  • @Pointy - that's the part I was trying to figure out. – John Jun 22 '22 at 16:33

1 Answers1

1

Adding script tags using innerHTML won't execute those tags

Not even adding them through other methods like using DOMParser works

What you need to do is for each script tag you added, you use document.createElement('script') and duplicate the content, then add it to the DOM

  
const html = `<h1>Hello!</h1>
<scrpt>function injectedJS() {var foo='bar';}</scrpt>`.replaceAll('scrpt', 'script');
// ignore the replaceAll - seems snippets are careful about script tags - this is just dummying up the received data anyway

function main() {

  // this is what you put inside
  //   if (xhttp.readyState == 4 && xhttp.status == 200) {

  const tgt = document.getElementById('testDiv');
  
  // add the html to the target node
  tgt.innerHTML = html;

  // process any script tags in the target node
  tgt.querySelectorAll('script').forEach(scr => {

    // create a new script tag
    const newscript = document.createElement('script');

    // copy the contents to the new script tag
    newscript.textContent = scr.textContent;

    // add new script directly after the current location
    scr.insertAdjacentElement('afterend', newscript);

    // remove old script - not strictly required
    scr.remove();
  });

  if (typeof injectedJS === "function") {
    console.log('yes');
  } else {
    console.log("no");
  }
}
main();
<div>Test</div>
<div id="testDiv"></div>

By the way, instead of

xhttp.onreadystatechange = function(){
    if (xhttp.readyState == 4 && xhttp.status == 200) {
        // your code
    }
}

do

xhttp.onload = function(){
    // your code
}

or better still use fetch for cleaner looking code, but that's just opinion so not important

Bravo
  • 6,022
  • 1
  • 10
  • 15
  • Thanks Bravo! That worked perfectly in the actual project. I'll look at fetch API for the ajax stuff. – John Jun 22 '22 at 16:39