0

I read and I tried many methods from posts and from Google on how to get the AJAX .responseText to allow JS to run and none of the methods either don't work or gave glitchy results I need a working method that works with insertAdjacentHTML properly.

code

a.php

<style>
  #main {
    max-height: 800px;
    width: 400px;
    display: -webkit-flex; /* Safari */
    -webkit-flex-direction: column-reverse; /* Safari 6.1+ */
    display: flex;
    flex-direction: column-reverse;
    overflow: auto;
  }
</style>

<script>
  document.addEventListener('DOMContentLoaded', function(){ 

    document.querySelector('#executeAjax').addEventListener('click', sendAjax);

    function sendAjax(){
      var xhr= new XMLHttpRequest();
      xhr.onreadystatechange = function(){

        if(xhr.readyState === 4){
          document.querySelector('#ajax').insertAdjacentHTML('beforeend', xhr.responseText);
        }
      }

      xhr.open('POST','b.php'); 
      xhr.send();
    }

  });

</script>

<button id='executeAjax'>Execute</button>

<div id="main">
  <div id='ajax'></div>
</div>

b.php

<style>
iframe{
  display: block;
  width: 100px;
  height: 100px;
}
</style>

<script>
   alert('Hello');
</script>

<script>
   alert('Hello again');
</script>

<iframe src="https://www.youtube.com/embed/tgbNymZ7vqY"></iframe>
u-ways
  • 6,136
  • 5
  • 31
  • 47
  • https://stackoverflow.com/questions/4619668/executing-script-inside-div-retrieved-by-ajax – cagri Sep 06 '18 at 22:01
  • There are multiple ways, you could for example get the scripts by regex out of the ajax response and then eval it all. – BlackNetworkBit Sep 06 '18 at 22:14
  • Thanks for your reply sh4dowb I already tried those methods from that post it don't work well or don't work at all with insertAdjacentHTML and I basically need it to execute the script on b.php you have any other ideas? –  Sep 06 '18 at 22:22
  • Hello BlackNetworkBit thanks for responding can you give a code example what you mean, if that is possible? So I can understand more in depth what you have in mind on how it will look like. –  Sep 06 '18 at 22:26
  • `get the scripts by regex ` - so, parse HTML using regex? perhaps read https://stackoverflow.com/a/1732454/5053002 before suggesting that @BlackNetworkBit :p – Jaromanda X Sep 06 '18 at 23:38
  • check [this code](https://pastebin.com/1jnLhM1h) it should also work with script's that have src attribute rather than inline code – Jaromanda X Sep 07 '18 at 00:09
  • Thanks for your reply Jaromanda X but I tried your code and at first it worked but I wanted to test something by adding another script tag look at my posted answer I made reference to rmn not in the comments section and imagine your code in those script tags instead of his code and it generates the same effect as rmn read what I said to rmn to know what I mean. –  Sep 07 '18 at 01:49
  • @Jaromanda X yeah you are right :) then i would suggest sending a json response which then gets decoded where the script then takes the evalscript from the json object. – BlackNetworkBit Sep 07 '18 at 11:05
  • @fsofb - absolutely no idea what you're talking about "at first it worked" ... well, what did **you** do to **break** it - it either works or it doesn't – Jaromanda X Sep 08 '18 at 03:00
  • if it's to do with "prevent running the same code twice" like you asked with your alternate account - https://pastebin.com/9g2gexbS ... use that in combination with giving each script tag in b.php a **unique id** ... e.g `` and `` – Jaromanda X Sep 08 '18 at 03:07

2 Answers2

0

After you have insertAdjacentHTML-ed, how about eval-ing the scripts manually.

document.querySelectorAll('#ajax script').forEach(script => {
    script.remove()
    eval(script.innerHTML)
})
rmn
  • 1,119
  • 7
  • 18
  • rmn thanks for your reply, look at my posted answer that I referenace to you to see whats going on now with new problems –  Sep 07 '18 at 01:34
  • Sorry I forgot to add the other parts of that answer so I just updated my new posted answer reference to you rmn let me know what you think can be the solution to your code –  Sep 07 '18 at 01:46
  • How can I get this "document.querySelectorAll('#ajax script').forEach(script => { script.remove() eval(script.innerHTML) })" to work on internet explorer I just notice that .remove() don't work on internet explorer –  Sep 07 '18 at 21:11
  • Replace `script.remove()` with `script.parentNode.removeChild(script)`. – rmn Sep 07 '18 at 21:14
  • It still does not work the console is showing that the error is coming from this line "document.querySelectorAll('#results script').forEach(script => {" the cursor in the console moves to this part of it => –  Sep 07 '18 at 21:22
  • Looks like you're on an older browser where arrow functions are not working, try replacing `script =>` with `function(script)`. – rmn Sep 07 '18 at 21:24
  • Now the cursor moved to the same line but behind document this what I just put document.querySelectorAll('#results script').forEach(function(script) { script.parentNode.removeChild(script) eval(script.innerHTML) }) –  Sep 07 '18 at 21:28
  • Not sure what do you mean? Did it work, or is it showing an error? – rmn Sep 07 '18 at 21:29
  • It still shows an error but it said this on why it is an error Object doesn't support property or method 'forEach' –  Sep 07 '18 at 21:30
  • What version of IE are you on? – rmn Sep 07 '18 at 21:31
  • I'm on the last version of internet explorer which is IE 11 –  Sep 07 '18 at 21:32
  • So, looks like IE11 doesn't support querySelectorAll on NodeList, see [this](https://stackoverflow.com/a/41142999/2206733) answer for resolution. – rmn Sep 07 '18 at 21:36
  • @rmn - you mean it doesn't support forEach on NodeList returned by querySelectorAll :p – Jaromanda X Sep 08 '18 at 03:01
0

If I understand the question correctly, and some of the "issues" you've mentioned in comments (and other questions), the EASIEST solution is to refactor your code so that the response in B.PHP is just the iframe src value (i.e. no need for HTML), and just create an iframe and set the source -

since, as far as I can tell from comments, the style/script tags are the same each time, you can programatically just get some other AJAX for those elements once - but I'm not going to present code for that, as that is extremely simple

Instead, a solution with minimal changes to what is output in B.PHP

Firstly, give the "unique" (i.e. the bits you only want to load/run once) elements that are returned in the b.php response an ID

<style id="onlyOnce1">
iframe{
  display: block;
  width: 100px;
  height: 100px;
}
</style>

<script id="onlyOnce2">
   alert('Hello');
</script>

<script id="onlyOnce3">
   alert('Hello again');
</script>

<iframe src="https://www.youtube.com/embed/tgbNymZ7vqY"></iframe>

Now, the loadHTML code I suggested earlier:

function loadHTML(text, dest, replace) {
    if (typeof dest == 'string') {
        dest = document.querySelector(dest);
    }
    var p = new DOMParser();
    var doc = p.parseFromString(text, 'text/html');
    var frag = document.createDocumentFragment();
    var id;
    while (doc.head.firstChild) {
        id = doc.head.firstChild.id;
        if(!(id && document.getElementById(id))) {
            // only add if id is not in DOM already
            frag.appendChild(doc.head.firstChild);
        }
    }
    while (doc.body.firstChild) {
        id = doc.head.firstChild.id;
        if(!(id && document.getElementById(id))) {
            // only add if id is not in DOM already
            frag.appendChild(doc.head.firstChild);
        }
    }
    [].forEach.call(frag.querySelectorAll('script'), function(script) {
        const scriptParent = script.parentNode || frag;
        const newScript = document.createElement('script');
        if (script.src) {
            newScript.src = script.src;
        } else {
            newScript.textContent = script.textContent;
        }
        scriptParent.replaceChild(newScript, script);
    });
    if (replace) {
        dest.innerHTML = '';
    }
    dest.appendChild(frag);
};

You'd change your XHR code as follows

document.addEventListener('DOMContentLoaded', function() { 
    document.querySelector('#executeAjax').addEventListener('click', sendAjax);
    function sendAjax() {
        const xhr = new XMLHttpRequest();
        xhr.addEventListener('load', function() {
            loadHTML(xhr.responseText, '#ajax');
        });
        xhr.open('POST','b.php'); 
        xhr.send();
    }
});

Now, the FIRST time you loadHTML is called, all elements will be added - but on second and subsequent calls, the "already" included elements with a particular ID (style and script in the above example) will not be loaded into the DOM again

Jaromanda X
  • 53,868
  • 5
  • 73
  • 87
  • Hey Jaromanda X thanks for reaching out to me still I really appreciate your wisdom on codding I am not ignoring you I will try your solution soon I'm dealing with personal things right now and coding demands i'll try this soon ok –  Sep 08 '18 at 08:34