Esecuzione di <script> iniettato da innerHTML dopo la chiamata AJAX


100

C'è un div chiamato "Content":

<div id="content"></div>

Dovrebbe essere riempito con i dati da un file PHP, da AJAX, incluso un <script>tag. Tuttavia, lo script all'interno di questo tag non viene eseguito.

<div id="content"><!-- After AJAX loads the stuff that goes here -->
   <script type="text/javascript">
     //code
   </script>
   <!-- More stuff that DOES work here -->
</div>

Come stai caricando il div? dipende dalla libreria che usi, puoi normalmente controllare se vuoi solo eseguire gli script dopo il caricamento di ajax.
Bill Yang

1
Dopo window.onloadaver creato un XMTHttpRequestoggetto per richiedere un'altra pagina (php) che contiene il contenuto del div, incluso uno script. Lo sto facendo con un semplice JS, senza librerie (oltre al mio lol)
JCOC611

Risposte:


65

JavaScript inserito come testo DOM non verrà eseguito. Tuttavia, puoi utilizzare il modello di script dinamico per raggiungere il tuo obiettivo. L'idea di base è spostare lo script che si desidera eseguire in un file esterno e creare un tag di script quando si riceve la risposta Ajax. Quindi si imposta l' srcattributo del tag di script e voilà, carica ed esegue lo script esterno.

Anche questo altro post StackOverflow potrebbe esserti utile: gli script possono essere inseriti con innerHTML? .


puoi selezionare tutti gli script caricati ed eseguirli con la funzione eval ():$('#audit-view script').each(function (index, element) { eval(element.innerHTML); })
Jerzy Gebler

Javascript aggiunto alla pagina dovrebbe assolutamente essere eseguito. ( jsfiddle.net/wnn5fz3m/1 ad esempio). La domanda è: perché a volte non lo fa?
NoBugs

@Chocula ho spostato il mio script in un file separato ma non funziona da parziale, potete aiutarmi con questo? stackoverflow.com/questions/42941856/…
Samra

Cordiali saluti (@NoBugs mi dà un indizio). Ho provato javascirpt semplice element.innerHTML = zzz e desnt funziona. Quindi provo Jquery $ (element) .html (zzz) e ho funzionato.
gtryonp

66

Ho usato questo codice, funziona bene

var arr = MyDiv.getElementsByTagName('script')
for (var n = 0; n < arr.length; n++)
    eval(arr[n].innerHTML)//run script inside div

4
Se me lo chiedi, questa è una risposta di gran lunga migliore di quella accettata. Questa è praticamente l'iniezione di JavaScript.
Xedret,

Sebbene utile, questo in realtà non risponde alla domanda sul perché gli script non vengano eseguiti. Vedi ad esempio jsfiddle.net/fkqmcaz7 e jsfiddle.net/wnn5fz3m/1 Dovrebbe assolutamente funzionare, e non trovo un caso semplificato in cui non funziona.
NoBugs

1
@NaoiseGolden OP chiede letteralmente dell'esecuzione dello script, quindi penso che vada bene qui. :-)
gira il

1
Eval () non è altamente raccomandato. Vedi questo - stackoverflow.com/questions/9107847/…
Kings

15

Se carichi un blocco di script all'interno del tuo div tramite Ajax in questo modo:

<div id="content">
    <script type="text/javascript">
    function myFunction() {
      //do something
    }
    myFunction();
    </script>
</div>

... aggiorna semplicemente il DOM della tua pagina, myFunction () non viene necessariamente chiamata.

È possibile utilizzare un metodo di callback Ajax come quello nel metodo ajax () di jQuery per definire cosa eseguire al termine della richiesta.

Quello che stai facendo è diverso dal caricare una pagina con JavaScript incluso sin dall'inizio (che viene eseguito).

Un esempio di come utilizzare il callback di successo e il callback di errore dopo aver recuperato alcuni contenuti:

  $.ajax({
    type: 'GET',
    url: 'response.php',
    timeout: 2000,
    success: function(data) {
      $("#content").html(data);
      myFunction();
    },
    error: function (XMLHttpRequest, textStatus, errorThrown) {
      alert("error retrieving content");
    }

Un altro modo rapido e sporco è usare eval () per eseguire qualsiasi codice di script che hai inserito come testo DOM se non vuoi usare jQuery o un'altra libreria.


usando il callback di jQuery, come potrei "eseguire" il codice all'interno del nuovo <script>?
JCOC611

Ho aggiunto un esempio di utilizzo della richiamata riuscita:
Christopher Tokar

1
Grazie mille! il "myFunction ();" parte era quello che stavo lasciando fuori dal mio codice.
Jason

11

Ecco lo script che valuterà tutti i tag script nel testo.

function evalJSFromHtml(html) {
  var newElement = document.createElement('div');
  newElement.innerHTML = html;

  var scripts = newElement.getElementsByTagName("script");
  for (var i = 0; i < scripts.length; ++i) {
    var script = scripts[i];
    eval(script.innerHTML);
  }
}

Basta chiamare questa funzione dopo aver ricevuto il codice HTML dal server. Attenzione: l'utilizzo evalpuò essere pericoloso.

Demo: http://plnkr.co/edit/LA7OPkRfAtgOhwcAnLrl?p=preview


5

Questo "funziona" per me usando jQuery, a condizione che non provi ad aggiungere un sottoinsieme dell'HTML restituito da XHR al documento. (Vedi questo bug report che mostra il problema con jQuery.)

Ecco un esempio che ne mostra il funzionamento:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> 
<html lang="en"> 
<head> 
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
    <title>test_1.4</title> 
    <script type="text/javascript" charset="utf-8" src="jquery.1.4.2.js"></script> 
    <script type="text/javascript" charset="utf-8"> 
        var snippet = "<div><span id='a'>JS did not run<\/span><script type='text/javascript'>" +
        "$('#a').html('Hooray! JS ran!');" +
        "<\/script><\/div>";
        $(function(){
            $('#replaceable').replaceWith($(snippet));
        });
    </script> 
</head> 
<body> 
    <div id="replaceable">I'm going away.</div> 
</body> 
</html>

Ecco l'equivalente di quanto sopra: http://jsfiddle.net/2CTLH/


1
Molto improbabile che questa sia la soluzione al problema al momento, poiché si trattava di un bug con una versione molto vecchia di jQuery.
NoBugs

3

Ecco una funzione che puoi usare per analizzare le risposte AJAX, specialmente se usi minifiedjs e vuoi che esegua il Javascript restituito o vuoi semplicemente analizzare gli script senza aggiungerli al DOM, gestisce anche gli errori di eccezione. Ho usato questo codice nella libreria php4sack ed è utile al di fuori della libreria.

function parseScript(_source) {
    var source = _source;
    var scripts = new Array();

    // Strip out tags
    while(source.toLowerCase().indexOf("<script") > -1 || source.toLowerCase().indexOf("</script") > -1) {
        var s = source.toLowerCase().indexOf("<script");
        var s_e = source.indexOf(">", s);
        var e = source.toLowerCase().indexOf("</script", s);
        var e_e = source.indexOf(">", e);

        // Add to scripts array
        scripts.push(source.substring(s_e+1, e));
        // Strip from source
        source = source.substring(0, s) + source.substring(e_e+1);
    }

    // Loop through every script collected and eval it
    for(var i=0; i<scripts.length; i++) {
        try {
          if (scripts[i] != '')
          {         
            try  {          //IE
                  execScript(scripts[i]);   
      }
      catch(ex)           //Firefox
      {
        window.eval(scripts[i]);
      }   

            }  
        }
        catch(e) {
            // do what you want here when a script fails
         // window.alert('Script failed to run - '+scripts[i]);
          if (e instanceof SyntaxError) console.log (e.message+' - '+scripts[i]);
                    }
    }
// Return the cleaned source
    return source;
 }

2

Se stai iniettando qualcosa che necessita del tag script, potresti ricevere un errore di sintassi non rilevato e dire token illegale . Per evitare ciò, assicurati di evitare le barre nel tag di chiusura dello script. ie;

var output += '<\/script>';

Lo stesso vale per qualsiasi tag di chiusura, come un tag form.


0

Ho avuto un post simile qui, caricamento addEventListener su caricamento ajax SENZA jquery

Come ho risolto il problema è stato inserire chiamate a funzioni all'interno della mia funzione stateChange. La pagina che avevo impostato era composta da 3 pulsanti che caricavano 3 pagine diverse in contentArea. Poiché dovevo sapere quale pulsante veniva premuto per caricare la pagina 1, 2 o 3, potevo facilmente usare le istruzioni if ​​/ else per determinare quale pagina viene caricata e quindi quale funzione eseguire. Quello che stavo cercando di fare era registrare diversi listener di pulsanti che funzionassero solo quando la pagina specifica veniva caricata a causa degli ID elemento.

così...

se si sta caricando (page1, pageload = 1) eseguire la funzione registerListeners1

poi lo stesso per pagina 2 o 3.


0

Questo ha funzionato per me chiamando eval su ogni contenuto dello script da ajax .done:

$.ajax({}).done(function (data) {      
    $('div#content script').each(function (index, element) { eval(element.innerHTML); 
})  

Nota: non ho scritto parametri in $ .ajax che devi regolare in base al tuo ajax.


0

La mia conclusione è che l'HTML non consente i tag NESTED SCRIPT. Se stai usando javascript per inserire codice HTML che include tag di script all'interno non funzionerà perché il javascript va anche in un tag di script. Puoi testarlo con il codice successivo e vedrai che non funzionerà. Il caso d'uso è che stai chiamando un servizio con AJAX o simili, stai ottenendo HTML e vuoi iniettarlo direttamente nel DOM HTML. Se il codice HTML inserito ha all'interno tag SCRIPT non funzionerà.

<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"></head><body></body><script>document.getElementsByTagName("body")[0].innerHTML = "<script>console.log('hi there')</script>\n<div>hello world</div>\n"</script></html>

-3

Un'altra cosa da fare è caricare la pagina con uno script come:

<div id="content" onmouseover='myFunction();$(this).prop( 'onmouseover', null );'>
<script type="text/javascript">
function myFunction() {
  //do something
}
myFunction();
</script>
</div>

Questo caricherà la pagina, quindi eseguirà lo script e rimuoverà il gestore eventi quando la funzione è stata eseguita. Questo non verrà eseguito immediatamente dopo un caricamento ajax, ma se stai aspettando che l'utente inserisca l'elemento div, funzionerà perfettamente.

PS. Richiede Jquery

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.