2011-11-22 17 views
6

supponiamo di avere una semplice pagina web che carica dinamicamente i contenuti che assomiglia a questo:Dove vengono caricati gli script dopo una chiamata ajax?

- main.html -

<!DOCTYPE html> 
<html xmlns="https://www.w3.org/1999/xhtml"> 
<head> 
<script type="text/javascript" 
    src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-1.6.2.js"> 
</script> 
<script type="text/javascript"> 
$(function() { 
    $.ajax({ 
     type: 'get', cache: false, url: '/svc.html', 
     success: function(h) { 
      $('#main').html(h); 
     } 
    }); 
}); 
</script> 
</head> 

<body> 
    <div id='main'> 
    loading... 
    </div> 
</body> 
</html> 

e che la pagina si carichi usa un po 'di JavaScript in un file separato :

- svc.html -

<script type="text/javascript" 
    src="https://ajax.aspnetcdn.com/ajax/jquery/jquery-1.6.2.js"> 
</script> 
<script type="text/javascript" src="/plugin.js" css="/plugin.css"></script> 
<div id='inner'> 
dynamically loaded content 
</div> 

notate l'attributo css sul tag script - indica un foglio di stile che appartiene allo script e che lo script caricherà per noi. Ecco lo script:

- plugin.js -

var css = $('<link />', { 
    rel: "stylesheet", type: "text/css", href: $('script:last').attr('css') 
}); 
$('head').append(css); 

e, infine, il foglio di stile, che si limitano a colori la inner div che viene caricato, come prova che funziona il tutto:

- plugin.css -

#inner 
{ 
    border: solid 1px blue; 
} 

ora, si noterà la il foglio di stile viene caricato: guardiamo allo $('script') e prendiamo l'ultimo, quindi prendiamo l'attributo css e alleghiamo un articolo link all'inizio del documento.

posso visitare /svc.html e le piste javascript, carichi il mio foglio di stile, tutto è fresco - tuttavia, se visito /main.html, le piste javascript, ma non riesce a trovare il caricamento del plugin.js nella matrice di $('script') (e quindi non riesce per caricare il foglio di stile). Si noti che lo script del plugin viene eseguito, ma non si vede da solo.

È un bug? una limitazione del metodo jQuery AJAX? non dovrebbe $('script') riflettere tutti gli script che sono stati caricati?

* Edit *

dopo molto pianto e stridore di denti, ho deciso di andare per la soluzione di Kevin B, però, non riesco a farlo funzionare, fondamentalmente perché il codice plugin.js viene eseguito al momento viene inserito il codice scriptNode, ma all'interno del codice del plugin il nodo non è ancora stato inserito e quindi non è disponibile nell'array $('script'), quindi sono ancora SOL. Ho messo tutto il codice per la revisione qui:

http://www.arix.com/tmp/loadWithJs/

risposta

5

Il codice jQuery che aggiunge HTML al DOM sempre strisce fuori <script> tag. Li gestisce e poi li getta via.

Un'eccezione a tale comportamento è quando si utilizza "$.load()" con l'hack che permette di caricare un frammento di una pagina:

$.load("http://something.com/whatever #stuff_I_want", function() { ... }); 

In tal caso, gli script sono spogliato e non valutato/run

+0

oh ... come brutto. Ho testato l'approccio '$ ('# main'). Load()' e sembra comportarsi allo stesso modo. * * * esegue lo script ma lo getta anche via ... – ekkis

+0

Esegue gli script quando ** non ** esegue l'hack speciale per selezionare solo un frammento dell'HTML restituito dalla chiamata AJAX. – Pointy

+0

oh, capisco ... quindi sembra che il codice bestiale di Kevin B potrebbe essere la mia unica alternativa. grr ... – ekkis

1

è possibile utilizzare $.. ajax per ottenere il codice HTML, striscia fuori lo script tag da soli, aggiungere il contenuto e quindi aggiungere il tag script nella posizione nel DOM in cui si desidera in modo che esso esegue il modo in cui si desidera.

$.ajax({...}).done(function(html){ 
    var htmlToAppend = html; 

    // replace all script tags with divs 
    htmlToAppend.replace(/<script/ig,"<div class='script'"); 
    htmlToAppend.replace(/<\/script>/ig,"</div>"); 

    // detach script divs from html 
    htmlToAppend = $(htmlToAppend); 
    var scripts = htmlToAppend.find(".script").detach(); 

    // append html to target div 
    htmlToAppend.appendTo("#target"); 

    // loop through scripts and append them to the dom 
    scripts.each(function(){ 
    var $script = $(this), 
     scriptText = $script.html(), 
     scriptNode = document.createElement('script'); 

    $(scriptNode).attr('css', $script.attr('css'); 
    scriptNode.appendChild(document.createTextNode(scriptText)); 
    $("#target")[0].appendChild(scriptNode); 
    }); 

}); 

Non ho testato questo codice, ma si basa sul codice di h istory.js

Edit: ecco una soluzione più semplice più su misura per le vostre esigenze:

$("#target").load(url,function(obj){ 
    // get css attribute from script tag using the raw returned html 
    var cssPath = obj.responseText.match(/css="(.*)"/i)[1]; 
    $('<link />', { 
     rel: "stylesheet", type: "text/css", href: cssPath 
    }).appendTo('head'); 

}); 

dal .load() spoglia i tag di script e poi li esegue, questo leggerà il testo di risposta crudo e ottenere il percorso css da esso, quindi aggiungere l'elemento link.

Non sono del tutto sicuro del motivo per cui viene gestito in questo modo.

Modifica: vedere il commento.

$.ajax({...}).done(function(html){ 
    $("#target")[0].innerHTML = html; 
}); 
+0

cosa diavolo erano gli sviluppatori di jQuery a pensare a questo ??? – ekkis

+0

ok, permettimi di reindirizzare la domanda: se volevo prendere l'attributo 'css' su il tag script che mi ha invocato, come potrei farlo, a parte il modo in cui lo sto facendo attualmente? – ekkis

+0

sì, la soluzione che proponi funzionerà. il problema è che volevo gestire quello all'interno dello script invocato in modo tale che il chiamante non debba essere responsabile di tale trattamento speciale – ekkis

0

Uno dei problemi qui è che NON È POSSIBILE ricaricare il jQuery in ogni pagina. Solo la pagina principale dovrebbe avere la chiamata jQuery:

<script type='text/javascript' src='jQuery-url'></script> 

O solo una pagina può chiamare e solo i bambini (sì, le pagine .LOADed da lì) sarà in grado di utilizzare jQuery.

Mi sono imbattuto in questo alcune volte prima di imparare la lezione. Questa potrebbe non essere l'intera risposta ai tuoi problemi ma potrebbe essere l'inizio di risolverli.

+0

L'ho caricata nella pagina * child * solo perché è possibile chiamarla direttamente e vedere che senza jQuery .load() nel mezzo tutto funziona come dovrebbe ma non è necessario e l'ho rimosso dalla versione che ho a arix.com - senza risolvere il problema – ekkis

1

La mia soluzione sarebbe piuttosto semplice

Perché non caricare i file necessari principale, il primo carico di tutto insieme? Quindi hai semplicemente un evento listener. (Controllare se il contenuto viene caricato semplicemente?)

L'unica soluzione per il caricamento su richiesta ...

Si deve semplicemente AJAX chiamare il file script stesso ...

<script type="text/javascript"> 
$(function() { 
    $.ajax({ 
     type: 'get', 
     cache: false, 
     url: 'svc.html', 
      success: function(response) { 
       if (response) { // If any response aka, loaded the svc.html file... 
        $('#main').html(response); 
        $.ajax({ 
         url: 'plugin.js', 
         dataType: 'script', 
         success: function(reponse) { 
          // You can now do something with the response here even... 
         } 
        }); 
       } 
      } 
    }); 
}); 
</script> 

My way

Effettuare qualche tipo di caricatore sulla pagina effettiva al caricamento prima di visualizzare qualsiasi cosa. (Un sacco di tutorial con jQuery sul Web per questo.)

+0

Penso che non sia possibile eseguire Javascript più e più volte, senza alcun tipo di "sforzo", è perché sarebbe un modo per frenare facilmente, e fare semplicemente rifare quel compito un milione di volte. (E il tuo server non ti piacerebbe per questo, ma solo una teoria.) –

+0

hei Daniel, grazie per esserti unito! i file di precaricamento non sono adatti perché a seconda di ciò che l'utente vuole fare caricheremo file diversi, quindi caricare tutto sarebbe costoso e non molto utile – ekkis

+0

Prego. nemmeno un'ora. Dovrebbe dormire. ^^ Hehe. (La maledizione di essere un coder di volta in volta.) –

0

ok, dopo molte lotte, ho implementato la soluzione di Kevin B in un plugin utile agli altri. I miglioramenti sono benvenuti! (dovrei forse metterlo in github?)

- loadWithJs.js -

// inspired by Kevin B's suggestions 
// at: http://stackoverflow.com/questions/8234215/where-are-scripts-loaded-after-an-ajax-call 

(function ($) { 
    $.fn.loadWithJs = function (o) { 
     var target = this; 
     var success = o.success; 

     o.success = function (html) { 
      // convert script tags 
      html = $('<div />').append(
       html.replace(/<(\/)?script/ig, "<$1codex") 
      ); 
      // detach script divs from html 
      var scripts = html.find("codex").detach(); 
      // populate target 
      target.html(html.children()); 

      // loop through scripts and append them to the dom 
      scripts.each(function() { 
       var script = $(this)[0]; 
       var scriptNode = document.createElement('script'); 

       for (var i = 0; i < script.attributes.length; i++) { 
        var attr = script.attributes[i]; 
        $(scriptNode).attr(attr.name, attr.value); 
       } 
       scriptNode.appendChild(
        document.createTextNode($(script).html()) 
       ); 
       target[0].appendChild(scriptNode); 
      }); 

      if (success) success(); 
     }; 

     $.ajax(o); 
    }; 
})(jQuery); 

quindi il chiamante può fare:

$(function() { 
    $('#main').loadWithJs({ 
     type: 'get', cache: false, 
     url: '/svc.html', 
     success: function() { console.log('loaded'); } 
    }); 
}); 
+0

grr ... anche questa soluzione ha problemi: http://stackoverflow.com/questions/8283360/where-are- script-caricati-dopo-una-ajax-call-redux – ekkis

Problemi correlati