Menjalankan <script> disuntikkan oleh innerHTML setelah panggilan AJAX

100

Ada div yang disebut "Konten":

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

Ini harus diisi dengan data dari file PHP, oleh AJAX, termasuk <script>tag. Namun, skrip di dalam tag ini tidak sedang dijalankan.

<div id="content"><!-- After AJAX loads the stuff that goes here -->
   <script type="text/javascript">
     //code
   </script>
   <!-- More stuff that DOES work here -->
</div>
JCOC611
sumber
Bagaimana Anda memuat div? bergantung pada pustaka yang Anda gunakan, Anda biasanya dapat mengontrol apakah Anda hanya ingin menjalankan skrip setelah ajax dimuat.
Bill Yang
1
Setelah window.onloadsaya membuat XMTHttpRequestobjek untuk meminta halaman (php) lain yang berisi konten div, termasuk skrip. Saya melakukan ini dengan JS biasa, tanpa perpustakaan (selain lol saya sendiri)
JCOC611

Jawaban:

65

JavaScript yang dimasukkan sebagai teks DOM tidak akan dijalankan. Namun, Anda dapat menggunakan pola skrip dinamis untuk mencapai tujuan Anda. Ide dasarnya adalah memindahkan skrip yang ingin Anda jalankan ke dalam file eksternal dan membuat tag skrip saat Anda mendapatkan respons Ajax. Anda kemudian mengatur srcatribut tag skrip dan voila Anda, itu memuat dan menjalankan skrip eksternal.

Posting StackOverflow lainnya ini juga dapat membantu Anda: Dapatkah skrip disisipkan dengan innerHTML? .

Chocula
sumber
Anda dapat memilih semua skrip yang dimuat dan menjalankannya dengan fungsi eval ():$('#audit-view script').each(function (index, element) { eval(element.innerHTML); })
Jerzy Gebler
Javascript yang ditambahkan ke halaman harus dijalankan. ( jsfiddle.net/wnn5fz3m/1 misalnya). Pertanyaannya adalah mengapa terkadang tidak?
NoBugs
@ Chocula saya memindahkan skrip saya ke file terpisah masih tidak berfungsi dari sebagian, bisakah Anda membantu dengan ini? stackoverflow.com/questions/42941856/…
Samra
FYI (@NoBugs memberi saya petunjuk). Saya mencoba elemen javascirpt biasa.innerHTML = zzz dan tidak bekerja. Kemudian saya mencoba Jquery $ (element) .html (zzz) dan berhasil.
gtryonp
66

Saya menggunakan kode ini, ini berfungsi dengan baik

var arr = MyDiv.getElementsByTagName('script')
for (var n = 0; n < arr.length; n++)
    eval(arr[n].innerHTML)//run script inside div
Firas Nizam
sumber
4
Jika Anda bertanya kepada saya, ini adalah jawaban yang jauh lebih baik daripada yang diterima. Ini adalah injeksi JavaScript yang cukup banyak.
Xedret
Meskipun berguna, ini benar-benar tidak menjawab pertanyaan mengapa skrip tidak dapat berjalan. Lihat misalnya jsfiddle.net/fkqmcaz7 dan jsfiddle.net/wnn5fz3m/1 Ini benar-benar harus berjalan, dan saya tidak menemukan kasus yang disederhanakan di mana ia tidak berfungsi.
NoBugs
1
@NaoiseGolden OP secara harfiah menanyakan tentang eksekusi skrip, jadi saya pikir tidak apa-apa di sini. :-)
thedayturns
1
Eval () sangat tidak disarankan. Lihat ini - stackoverflow.com/questions/9107847/…
Raja
15

Jika Anda memuat blok skrip dalam div Anda melalui Ajax seperti ini:

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

... itu hanya memperbarui DOM halaman Anda, myFunction () tidak selalu dipanggil.

Anda bisa menggunakan metode callback Ajax seperti yang ada di metode ajax () jQuery untuk menentukan apa yang harus dieksekusi ketika permintaan selesai.

Apa yang Anda lakukan berbeda dari memuat halaman dengan JavaScript yang disertakan di dalamnya dari awal (yang dieksekusi).

Contoh cara menggunakan callback sukses dan callback error setelah mengambil beberapa konten:

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

Cara cepat dan kotor lainnya adalah menggunakan eval () untuk mengeksekusi kode skrip apa pun yang Anda masukkan sebagai teks DOM jika Anda tidak ingin menggunakan jQuery atau pustaka lainnya.

Christopher Tokar
sumber
menggunakan callback jQuery, bagaimana saya bisa "mengeksekusi" kode di dalam <script> baru?
JCOC611
Saya menambahkan contoh penggunaan panggilan balik sukses:
Christopher Tokar
1
Terima kasih banyak! "myFunction ();" bagian adalah apa yang saya tinggalkan dari kode saya.
Jason
11

Berikut ini skrip yang akan mengevaluasi semua tag skrip dalam teks.

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);
  }
}

Panggil saja fungsi ini setelah Anda menerima HTML dari server. Berhati-hatilah: menggunakan evalbisa berbahaya.

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

Evgenii
sumber
5

Ini 'hanya berfungsi' untuk saya yang menggunakan jQuery, asalkan Anda tidak mencoba menambahkan subset HTML yang dikembalikan XHR ke dokumen. (Lihat laporan bug ini yang menunjukkan masalah dengan jQuery.)

Berikut adalah contoh yang menunjukkannya berfungsi:

<!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>

Berikut adalah persamaan di atas: http://jsfiddle.net/2CTLH/

Phrogz
sumber
1
Sangat tidak mungkin ini akan menjadi solusi untuk masalah saat ini, karena itu adalah bug dengan versi jQuery yang sangat lama.
NoBugs
3

Berikut adalah fungsi yang dapat Anda gunakan untuk mengurai tanggapan AJAX, terutama jika Anda menggunakan minifiedjs dan ingin menjalankan Javascript yang dikembalikan atau hanya ingin mengurai skrip tanpa menambahkannya ke DOM, fungsi ini juga menangani kesalahan pengecualian. Saya menggunakan kode ini di perpustakaan php4sack dan berguna di luar perpustakaan.

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;
 }
Andre Van Zuydam
sumber
2

Jika Anda memasukkan sesuatu yang membutuhkan tag skrip, Anda mungkin mendapatkan kesalahan sintaks yang tidak tertangkap dan mengatakan token ilegal . Untuk menghindari hal ini, pastikan untuk menghindari garis miring ke depan di tag skrip penutup Anda. yaitu;

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

Hal yang sama berlaku untuk semua tag penutup, seperti tag formulir.

TommyRay
sumber
0

Saya memiliki posting serupa di sini, addEventListener memuat pada ajax load TANPA jquery

Bagaimana saya mengatasinya adalah dengan memasukkan panggilan ke fungsi dalam fungsi stateChange saya. Halaman yang saya siapkan adalah 3 tombol yang akan memuat 3 halaman berbeda ke dalam contentArea. Karena saya harus tahu tombol mana yang ditekan untuk memuat halaman 1, 2 atau 3, saya dapat dengan mudah menggunakan pernyataan if / else untuk menentukan halaman mana yang sedang dimuat dan kemudian fungsi mana yang akan dijalankan. Apa yang saya coba lakukan adalah mendaftarkan pendengar tombol yang berbeda yang hanya akan bekerja ketika halaman tertentu dimuat karena ID elemen ..

begitu...

jika (halaman1 sedang dimuat, pageload = 1) jalankan fungsi registerListeners1

lalu sama untuk halaman 2 atau 3.

Richard Chase
sumber
0

Ini berfungsi untuk saya dengan memanggil eval pada setiap konten skrip dari ajax .done:

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

Catatan: Saya tidak menulis parameter ke $ .ajax yang harus Anda sesuaikan dengan ajax Anda.

shivgre.dll
sumber
0

Kesimpulan saya adalah HTML tidak mengizinkan tag NESTED SCRIPT. Jika Anda menggunakan javascript untuk memasukkan kode HTML yang menyertakan tag skrip di dalamnya tidak akan berfungsi karena javascript juga masuk dalam tag skrip. Anda dapat mengujinya dengan kode berikutnya dan Anda akan tahu bahwa itu tidak akan berhasil. Contoh kasusnya adalah Anda memanggil layanan dengan AJAX atau yang serupa, Anda mendapatkan HTML dan ingin langsung memasukkannya ke dalam DOM HTML. Jika kode HTML yang dimasukkan ada di dalam tag SCRIPT tidak akan bekerja.

<!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>
Antonio Martin
sumber
-3

Hal lain yang harus dilakukan adalah memuat halaman dengan skrip seperti:

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

Ini akan memuat halaman, kemudian menjalankan skrip dan menghapus pengendali event ketika fungsi telah dijalankan. Ini tidak akan berjalan segera setelah ajax dimuat, tetapi jika Anda menunggu pengguna untuk memasukkan elemen div, ini akan bekerja dengan baik.

PS. Membutuhkan Jquery

Joshua Klein
sumber