web-development-kb-es.site

¿Cómo se ejecuta un bloque de JavaScript cargado dinámicamente?

Estoy trabajando en una página web donde estoy haciendo una llamada AJAX que devuelve un fragmento de HTML como:

<div>
  <!-- some html -->
  <script type="text/javascript">
    /** some javascript */
  </script>
</div>

Estoy insertando todo en el DOM, pero el JavaScript no se está ejecutando. ¿Hay alguna forma de ejecutarlo?

Algunos detalles: no puedo controlar lo que hay en el bloque de secuencia de comandos (por lo que no puedo cambiarlo a una función que pueda llamarse), solo necesito que se ejecute todo el bloque. No puedo llamar a eval en la respuesta porque JavaScript está dentro de un bloque más grande de HTML. Podría hacer algún tipo de expresión regular para separar el JavaScript y luego llamar a eval, pero eso es bastante asqueroso. Alguien sabe una mejor manera?

38
kristina

El script agregado al configurar la propiedad innerHTML de un elemento no se ejecuta. Intenta crear un nuevo div, configura su innerHTML y luego agrega este nuevo div al DOM. Por ejemplo:

 <html> 
 <head> 
 <script type = 'text/javascript'> 
 function addScript () 
 {
 var str = "<script> alert ('estoy aquí'); <\/script>"; 
 var newdiv = document.createElement ('div'); 
 newdiv.innerHTML = str; 
 document.getElementById ('target'). appendChild (newdiv); 
} 
 </script> 
 </head> 
 <body> 
 <input type = "button" value = "add script" onclick = "addScript ()" />
 <div> hello world </div> 
 < div id = "target"> </div> 
 </body> 
 </html> 
16
Ed.

No tiene que usar regex si está usando la respuesta para llenar un div o algo así. Puede usar getElementsByTagName.

div.innerHTML = response;
var scripts = div.getElementsByTagName('script');
for (var ix = 0; ix < scripts.length; ix++) {
    eval(scripts[ix].text);
}
15
Scott Nichols

Mientras que la respuesta aceptada de @Ed. no funciona en las versiones actuales de Firefox, Google Chrome o los navegadores Safari que logré adaptar su ejemplo para invocar scripts agregados dinámicamente.

Los cambios necesarios son solo en la forma en que los scripts se agregan a DOM. En lugar de agregarlo como innerHTML, el truco fue crear un nuevo elemento de script y agregar el contenido del script real como innerHTML al elemento creado y luego agregar el elemento de script al objetivo real.

<html>
<head>
<script type='text/javascript'>
function addScript()
{
    var newdiv = document.createElement('div');

    var p = document.createElement('p');
    p.innerHTML = "Dynamically added text";
    newdiv.appendChild(p);

    var script = document.createElement('script');
    script.innerHTML = "alert('i am here');";
    newdiv.appendChild(script);

    document.getElementById('target').appendChild(newdiv);
}
</script>
</head>
<body>
<input type="button" value="add script" onclick="addScript()"/>
<div>hello world</div>
<div id="target"></div>
</body>
</html>

Esto funciona para mí en Firefox 42, Google Chrome 48 y Safari 9.0.3

8
Roman Vottner

Una alternativa es no simplemente volcar el retorno de la llamada Ajax en el DOM usando InnerHTML.

Puede insertar cada nodo dinámicamente y luego se ejecutará el script.

De lo contrario, el navegador simplemente asume que está insertando un nodo de texto e ignora los scripts.

Usar Eval es bastante malo, ya que requiere que se active otra instancia de Javascript VM y JIT la cadena pasada.

2
FlySwat

El mejor método probablemente sería identificar y evaluar el contenido del bloque de script directamente a través del DOM.

Sin embargo, sería cuidadoso ... si está implementando esto para superar una limitación de algunas llamadas fuera del sitio, está abriendo un agujero de seguridad.

Lo que implemente podría explotarse para XSS.

1
Quintin Robinson

Puede usar una de las bibliotecas populares de Ajax que hacen esto de forma nativa. Me gusta Prototipo . Simplemente puede agregar evalScripts: true como parte de su llamada Ajax y sucede de forma automática.