Chiamata di una funzione JavaScript restituita da una risposta Ajax

Ho un sistema in cui invio un comando Ajax, che restituisce un blocco di script con una funzione al suo interno. Dopo che questi dati sono stati inseriti correttamente nel DIV, voglio essere in grado di chiamare questa funzione per eseguire le azioni richieste.

È ansible?

Penso di interpretare correttamente la tua domanda sotto questo modulo: “OK, ho già finito con tutte le cose Ajax, vorrei solo sapere se la funzione JavaScript inserita dal callback Ajax nel DIV è richiamabile in qualsiasi momento da quel momento in poi , cioè, non voglio chiamarlo contestualmente al ritorno di callback “.

OK, se intendi qualcosa di simile la risposta è sì, puoi invocare il tuo nuovo codice in quel momento in qualsiasi momento durante la persistenza della pagina all’interno del browser, alle seguenti condizioni:

1) Il codice JavaScript restituito da Ajax callback deve essere sintatticamente OK;
2) Anche se la dichiarazione della funzione è inserita in un blocco all'interno di un elemento

esistente, il browser non saprà che la nuova funzione esiste, poiché il codice della dichiarazione non è mai stato eseguito. Pertanto, è necessario eval() il codice di dichiarazione restituito dal callback Ajax, al fine di dichiarare efficacemente la nuova funzione e renderla disponibile per tutta la durata della pagina.

Anche se abbastanza fittizio, questo codice spiega l'idea:

   

Non ho usato Ajax, ma il concetto è lo stesso (anche se l'esempio che ho scelto non è molto intelligente 🙂

In generale, non metto in discussione il progetto della soluzione, ovvero se sia più o meno appropriato esternare + generalizzare la funzione in un file .js separato e simili, ma si prega di prendere nota che tale soluzione potrebbe sollevare ulteriori problemi, specialmente se le vostre invocazioni Ajax dovrebbero ripetersi, cioè se il contesto della stessa funzione dovesse cambiare o nel caso in cui la persistenza della funzione dichiarata dovesse essere interessata, quindi forse dovreste seriamente considerare di cambiare il vostro disegno in uno degli esempi suggeriti in questa discussione.

Infine, se ho frainteso la tua domanda, e stai parlando dell'invocazione contestuale della funzione quando ritorna il callback Ajax, allora il mio sentimento è di suggerire l'approccio Prototype descritto da krosenvold , in quanto è cross-browser, testato e perfettamente funzionante, e questo può darti una migliore tabella di marcia per le future implementazioni.

Nota : eval () può essere facilmente utilizzato impropriamente, diciamo che la richiesta è intercettata da terzi e non ti invia codice attendibile. Quindi con eval () eseguiresti questo codice non affidabile. Fare riferimento qui per i pericoli di eval () .


All’interno del file HTML / Ajax / JavaScript restituito, avrai un tag JavaScript. Dagli un ID, come il runscript . Non è raro aggiungere un id a questi tag, ma è necessario fare riferimento in modo specifico.

  

Nella finestra principale, quindi chiama la funzione eval valutando solo quel NUOVO blocco di codice JavaScript (in questo caso, si chiama runscript ):

 eval(document.getElementById("runscript").innerHTML); 

E funziona, almeno in Internet Explorer 9 e Google Chrome.

E ‘completamente ansible, e ci sono anche alcuni casi d’uso abbastanza legittimi per questo. Usando il framework Prototype è fatto come segue.

 new Ajax.Updater('items', '/items.url', { parameters: { evalJS: true} }); 

Vedi la documentazione del programma di aggiornamento Ajax. Le opzioni sono nel set di opzioni comuni . Come al solito, ci sono alcuni avvertimenti su dove “questo” indica, quindi leggi la stampa fine.

Il codice JavaScript verrà valutato al caricamento. Se il contenuto contiene la funzione myFunc(), si potrebbe davvero dire myFunc() seguito. Forse come segue.

 if (window["myFunc"]) myFunc() 

Questo controlla se la funzione esiste. Forse qualcuno ha un modo migliore di fare cross-browser per ciò che funziona in Internet Explorer 6.

Sembra un design piuttosto strano per il tuo codice: in genere ha più senso che le tue funzioni vengano richiamate direttamente da un file js e quindi recuperare solo i dati con la chiamata Ajax.

Tuttavia, credo che dovrebbe funzionare chiamando eval () sulla risposta, a condizione che sia sintatticamente corretto codice JavaScript.

Con jQuery lo farei usando getScript

Basta ricordare se si crea una funzione il modo in basso attraverso ajax …

 function foo() { console.log('foo'); } 

… ed eseguirlo via eval, probabilmente avrai un problema di contesto. Prendi questo come funzione di callback:

 function callback(result) { responseDiv = document.getElementById('responseDiv'); responseDiv.innerHTML = result; scripts = responseDiv.getElementsByTagName('script'); eval(scripts[0]); } 

Dichiarerai una funzione all’interno di una funzione, quindi questa nuova funzione sarà accessibile solo su quell’ambito.

Se si desidera creare una funzione globale in questo scenario, è ansible dichiararlo in questo modo:

 window.foo = function () { console.log('foo'); }; 

Ma penso anche che non dovresti farlo …

Ci scusiamo per qualsiasi errore qui …

Vorrei aggiungere che c’è una funzione eval in jQuery che ti permette di valutare il codice globalmente che dovrebbe farti sbarazzare di qualsiasi problema contestuale. La funzione è chiamata globalEval () e ha funzionato benissimo per i miei scopi. La sua documentazione può essere trovata qui .

Questo è il codice di esempio fornito dalla documentazione dell’API jQuery:

 function test() { jQuery.globalEval("var newVar = true;") } test(); // newVar === true 

Questa funzione è estremamente utile quando si tratta di caricare script esterni in modo dinamico che apparentemente si stava tentando di fare.

Una lista di controllo per fare una cosa del genere:

  1. la risposta Ajax restituita è eval (ed).
  2. le funzioni sono dichiarate in forma func_name = function() {...}

Meglio ancora, usa i framework che lo gestiscono come in Prototype . Hai Ajax.updater .

Codice lato PHP Nome del file class.sendCode.php

 printCode($dateini,$datefin); } function printCode($dateini,$datefin){ $code =" alert ('code Coming from AJAX {$this->dateini} and {$this->datefin}');"; //Insert all the code you want to execute, //only javascript or Jquery code , dont incluce  

Ora dalla tua pagina Html devi triggersre la funzione Ajax per inviare i dati.

 ....  .... Date begin: 
Date end :

Ora nel nostro script.js locale definiremo l'ajax

 function triggerAjax() { $.ajax({ type: "POST", url: 'class.sendCode.php', dataType: "HTML", data : { dateini : $('#startdate').val(), datefin : $('#enddate').val()}, success: function(data){ $.globalEval(data); // here is where the magic is made by executing the data that comes from // the php class. That is our javascript code to be executed } }); } 

Questa non sembra una buona idea.

Dovresti astrarre la funzione per includere nel resto del tuo codice JavaScript i dati restituiti dai metodi Ajax.

Per quello che vale, però, (e non capisco perché stai inserendo un blocco di script in un div?) Anche i metodi di script inline scritti in un blocco di script saranno accessibili.

La mia solita funzione di chiamata ajax:

 function xhr_new(targetId, url, busyMsg, finishCB) { var xhr; if(busyMsg !== undefined) document.getElementById(targetId).innerHTML = busyMsg; try { xhr = new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) { try { xhr = new ActiveXObject('Microsoft.XMLHTTP'); } catch(e2) { try { xhr = new XMLHttpRequest(); } catch(e3) { xhr = false; } } } xhr.onreadystatechange = function() { if(xhr.readyState == 4) { if(xhr.status == 200) { var target = document.getElementById(targetId) target.innerHTML = xhr.responseText; var scriptElements = target.getElementsByTagName("script"); var i; for(i = 0; i < scriptElements.length; i++) eval(scriptElements[i].innerHTML); if(finishCB !== undefined) finishCB(); } else document.getElementById(targetId).innerHTML = 'Error code: ' + xhr.status; } }; xhr.open('GET', url, true); xhr.send(null); // return xhr; } 

Qualche spiegazione:
targetId è un ID elemento (di solito div) in cui andrà il testo del risultato della chiamata ajax.
url è l'url di chiamata ajax.
busyMsg sarà il testo temporaneo nell'elemento di destinazione.
finishCB verrà chiamato quando la transazione ajax è stata completata correttamente.
Come vedi in xhr.onreadystatechange = function() {...} tutti gli elementi saranno raccolti dalla risposta ajax e verranno eseguiti uno ad uno. Sembra funzionare molto bene per me. L'ultimo parametro è opzionale.

Ho provato questo e funziona. Qual è il problema? Basta inserire la nuova funzione all’interno dell’elemento javascript e quindi chiamarla. Funzionerà.

Ho provato tutte le tecniche offerte qui, ma alla fine il modo in cui funzionava era semplicemente mettere la funzione JavaScript all’interno della pagina / file in cui dovrebbe avvenire e chiamarla dalla parte di risposta dell’Ajax semplicemente come una funzione:

 ... }, function(data) { afterOrder(); } 

Questo ha funzionato al primo tentativo, quindi ho deciso di condividere.

Anche questo codice funziona, ma evalmo l’html che aggiungerò alla sceneggiatura

 function RunJS(objID) { //alert(http_request.responseText); var c=""; var ob = document.getElementById(objID).getElementsByTagName("script"); for (var i=0; i < ob.length - 1; i++) { if (ob[i + 1].text != null) c+=ob[i + 1].text; } var s = document.createElement("script"); s.type = "text/javascript"; s.text = c; document.getElementsByTagName("head")[0].appendChild(s); } 

Ho risolto questo oggi inserendo il mio JavaScript nella parte inferiore della risposta HTML.

Ho avuto una richiesta AJAX che ha restituito un sacco di codice HTML che è stato visualizzato in un overlay. Avevo bisogno di albind un evento click a un pulsante nella risposta HTML / overlay di risposta. In una pagina normale, avrei avvolto il mio JavaScript in un “window.onload” o “$ (document) .ready” in modo che collegasse il gestore di eventi all’object DOM dopo che il DOM per il nuovo overlay era stato reso, ma poiché si trattava di una risposta AJAX e non di un nuovo caricamento della pagina, quell’evento non è mai accaduto, il browser non ha mai eseguito il mio JavaScript, il mio gestore di eventi non è mai stato collegato all’elemento DOM e la mia nuova funzionalità non ha funzionato. Ancora una volta, ho risolto il mio “errore di esecuzione di JavaScript in un problema di risposta AJAX” non utilizzando “$ (document) .ready” nella testa del documento, ma posizionando il mio JavaScript alla fine del documento e facendolo scorrere dopo l’HTML / DOM era stato reso.

Se il tuo script AJAX impiega più di un paio di millisecondi per essere eseguito, eval () verrà sempre eseguito in anticipo e valuterà l’elemento di risposta vuoto prima che AJAX lo populi con lo script che stai tentando di eseguire.

Piuttosto che andare in giro con il timing e l’eval (), ecco una soluzione abbastanza semplice che dovrebbe funzionare nella maggior parte delle situazioni ed è probabilmente un po ‘più sicura. L’uso di eval () è generalmente disapprovato perché i personaggi valutati come codice possono essere facilmente manipolati dal lato client.

Concetto

  1. Includi la tua funzione javascript nella pagina principale. Scrivilo in modo che qualsiasi elemento dinamico possa essere accettato come argomento.
  2. Nel tuo file AJAX, chiama la funzione utilizzando un evento DOM ufficiale (onclick, onfocus, onblur, onload, ecc.) A seconda di quali altri elementi sono presenti nella tua risposta, puoi essere abbastanza furbo per renderlo trasparente. Passa i tuoi elementi dinamici come argomenti.
  3. Quando il tuo elemento di risposta viene popolato e l’evento ha luogo, la funzione viene eseguita.

Esempio

In questo esempio, voglio albind un elenco dinamico di completamento automatico dalla libreria jquery-ui a un elemento AJAX DOPO che l’elemento è stato aggiunto alla pagina. Facile, giusto?

start.php

    Demo             

ajaxRequest.php

 \n"; ?> 

La risposta di Federico Zancan è corretta, ma non devi dare alla tua sceneggiatura un ID e valutare tutto il tuo copione. Basta valutare il nome della tua funzione e può essere chiamato.

Per raggiungere questo objective nel nostro progetto, abbiamo scritto una funzione proxy per chiamare la funzione restituita all’interno della risposta Ajax.

 function FunctionProxy(functionName){ var func = eval(functionName); func(); }