Вызов функции JavaScript, возвращенной из ответа Ajax
У меня есть система, в которой я отправляю команду Ajax, которая возвращает блок скрипта с функцией в нем. После того, как эти данные правильно вставлены в DIV, я хочу иметь возможность вызывать эту функцию для выполнения необходимых действий.
это возможно?
17 ответов:
Я думаю, чтобы правильно интерпретировать ваш вопрос в этой форме:"хорошо, я уже закончил со всеми вещами Ajax; я просто хочу знать, если функция JavaScript мой Ajax обратный вызов вставлен в DIV вызывается в любое время с этого момента, то есть, я не хочу, чтобы вызвать его контекстуально к обратному вызову".
ОК, если вы имеете в виду что-то вроде этого ответ да, вы можете вызвать свой новый код к этому моменту в любое время во время сохранения страницы в браузере, при следующих обстоятельствах:
1) Ваш код JavaScript, возвращаемый Ajax callback, должен быть синтаксически ОК;
2) Даже если объявление функции вставлено в<script>блок в существующей<div>элемент, браузер не будет знать, что новая функция существует, так как код объявления никогда не выполнялся. Итак, вы должныeval()ваш код объявления, возвращенный обратным вызовом Ajax, чтобы эффективно объявить вашу новую функцию и иметь ее доступной во время целая страница жизни.даже если совсем пустышка, этот код объясняет идею:
<html> <body> <div id="div1"> </div> <div id="div2"> <input type="button" value="Go!" onclick="go()" /> </div> <script type="text/javascript"> var newsc = '<script id="sc1" type="text/javascript">function go() { alert("GO!") }<\/script>'; var e = document.getElementById('div1'); e.innerHTML = newsc; eval(document.getElementById('sc1').innerHTML); </script> </body> </html>Я не использовал Ajax, но концепция та же (даже если пример, который я выбрал, конечно, не очень умный :-)
вообще говоря, я не ставлю под сомнение ваш дизайн решения, т. е. более или менее целесообразно ли экстернализировать + обобщить функцию в отдельном .JS file и тому подобное, но обратите внимание, что такое решение может вызвать дальнейшие проблемы, особенно если ваши вызовы Ajax должны повторяться, т. е. если контекст одной и той же функции должен измениться или в случае сохранения объявленной функции, возможно, вам следует серьезно рассмотреть возможность изменения вашего дизайна на один из предложенных примеров в этом потоке.
наконец, если я неправильно понял ваш вопрос, А вы про контекстная вызов функции, когда возвращается ваш обратный вызов Ajax, то мое чувство состоит в том, чтобы предложить подход прототипа описал krosenvold, поскольку это кросс-браузер, протестированный и полностью функциональный, и это может дать вам лучшую дорожную карту для будущих реализаций.
Примечание: eval () можно легко злоупотреблять, скажем, что запрос перехватывается третьей стороной и отправляет вам не доверенный код. Тогда с eval () вы будете запускать этот не доверенный код. См. здесь опасности eval ().
внутри возвращенного файла HTML / Ajax / JavaScript у вас будет тег JavaScript. Дайте ему идентификатор, например runscript. Это необычно, чтобы добавить идентификатор к этим тегам, но это нужно было ссылаться на него конкретно.
<script type="text/javascript" id="runscript"> alert("running from main"); </script>в главном окне вызовите функцию eval, оценив только этот новый блок кода JavaScript (в данном случае он называется runscript):
eval(document.getElementById("runscript").innerHTML);и это работает, по крайней мере, в Internet Explorer 9 и Google Chrome.
это вполне возможно, и есть даже некоторые вполне законные варианты использования для этого. Используя прототип основа это делается следующим образом.
new Ajax.Updater('items', '/items.url', { parameters: { evalJS: true} });посмотреть документация из Ajax updater. Параметры находятся в настройки. Как обычно, есть некоторые предостережения о том, куда указывает "это", поэтому прочитайте мелкий шрифт.
код JavaScript будет оцениваться при загрузке. Если содержимое содержит функцию
myFunc(),вы могли бы просто сказатьmyFunc()потом. Может быть, следующим образом.if (window["myFunc"]) myFunc()это проверяет, если функция не существует. Возможно, у кого-то есть лучший кросс-браузерный способ сделать то, что работает в Internet Explorer 6.
Это кажется довольно странным дизайном для вашего кода-обычно имеет смысл, чтобы ваши функции вызывались непосредственно из a .JS-файл, а затем только извлекать данные с помощью вызова Ajax.
однако, я считаю, что он должен работать, позвонив eval () на ответ-при условии, что это синтаксически правильный код JavaScript.
с jQuery я бы сделал это с помощью getScript
просто помните, если вы создаете функцию, как показано ниже через ajax...
function foo() { console.log('foo'); }...и выполнить его через eval, вы, вероятно, получите проблему контекста. Возьмите это в качестве функции обратного вызова:
function callback(result) { responseDiv = document.getElementById('responseDiv'); responseDiv.innerHTML = result; scripts = responseDiv.getElementsByTagName('script'); eval(scripts[0]); }вы будете объявлять функцию внутри функции,поэтому эта новая функция будет доступна только в этой области.
Если вы хотите создать глобальную функцию в этом случае, можно объявить так:
window.foo = function () { console.log('foo'); };но, я тоже думаю ты не должен этого делать...
извините за любую ошибку здесь...
Я хотел бы добавить, что в jQuery есть функция eval, позволяющая вам оценивать код глобально, что должно избавить вас от любых контекстуальных проблем. Функция называется globalEval() и он работал большой для моих целей. Документацию можно найти здесь.
Это пример кода, предоставленный документацией API jQuery:
function test() { jQuery.globalEval("var newVar = true;") } test(); // newVar === trueэта функция чрезвычайно полезна, когда речь заходит о загрузке внешних скриптов динамически, что вы, по-видимому, пытались сделать.
контрольный список для выполнения такой вещи:
- возвращенный ответ Ajax-eval (ed).
- функции объявляются в форме
func_name = function() {...}еще лучше, используйте фреймворки, которые обрабатывают его, как в прототип. У вас есть
Ajax.updater.
код на PHP Имя класса файла.sendCode.php
<?php class sendCode{ function __construct($dateini,$datefin) { echo $this->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 <script> tags return $code ; } } new sendCode($_POST['dateini'],$_POST['datefin']);Теперь с вашей Html-страницы вы должны вызвать функцию ajax для отправки данных.
.... <script src="http://code.jquery.com/jquery-1.9.1.js"></script> .... Date begin: <input type="text" id="startdate"><br> Date end : <input type="text" id="enddate"><br> <input type="button" value="validate'" onclick="triggerAjax()"/>Теперь в нашем локальном скрипте.js определим 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 } }); }
Это не звучит как хорошая идея.
вы должны абстрагировать функцию для включения в остальную часть вашего кода JavaScript из данных, возвращаемых методами Ajax.
для чего это стоит, хотя, (и я не понимаю, почему вы вставляете блок скрипта в div?) даже встроенные методы скрипта, написанные в блоке скрипта, будут доступны.
моя обычная функция вызова 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; }объяснение:
targetId- это идентификатор элемента (обычно div), куда будет отправлен текст результата вызова ajax.url- это url-адрес вызова ajax.busyMsgбудет временный текст в целевом элементе.finishCBбудет вызван после успешного завершения транзакции ajax.
Как вы видите вxhr.onreadystatechange = function() {...}все<script>элементы будут собраны из ответа ajax и будут выполняться один за другим. Это, кажется, работает очень хорошо для меня. Два последних параметра являются необязательными.
Я проверил это, и это работает. В чем проблема? Просто поместите новую функцию в свой элемент javascript, а затем вызовите ее. Это сработает.
я попробовал все методы, предлагаемые здесь, но, наконец, способ, который работал, состоял в том, чтобы просто поместить функцию JavaScript внутри страницы / файла, где она должна произойти, и вызвать ее из ответной части Ajax просто как функцию:
... }, function(data) { afterOrder(); }это сработало с первой попытки, поэтому я решил поделиться.
этот код также работает, вместо того, чтобы eval html я собираюсь добавить скрипт в голову
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); }
Я решил это сегодня, поставив свой JavaScript в нижней части ответа HTML.
У меня был запрос AJAX, который вернул кучу HTML, которая отображалась в наложении. Мне нужно было прикрепить событие click к кнопке в возвращенном ответе HTML / overlay. На обычной странице Я бы обернул свой JavaScript в " окно.события onload" или "$(документ).ready", чтобы он прикрепил обработчик событий к объекту DOM после того, как DOM для нового наложения был визуализирован, но потому что это был ответ AJAX, а не новая загрузка страницы, это событие никогда не происходило, браузер никогда не выполнял мой JavaScript, мой обработчик событий никогда не привязывался к элементу DOM, и моя новая часть функциональности не работала. Опять же, я решил свою "выполнение JavaScript в проблеме ответа AJAX", не используя "$(document).готов " в голове документа, но поместив мой JavaScript в конец документа и запустив его после того, как HTML/DOM был отрисован.
Если ваш сценарий AJAX занимает более нескольких миллисекунд для запуска, eval () всегда будет работать вперед и оценивать пустой элемент ответа, прежде чем AJAX заполнит его сценарием, который вы пытаетесь выполнить.
вместо того, чтобы возиться со временем и eval(), вот довольно простой обходной путь, который должен работать в большинстве ситуаций и, вероятно, немного более безопасным. Использование eval () обычно не одобряется, потому что символы, оцениваемые как код, можно легко манипулировать клиентский.
концепция
- включите функцию javascript на главной странице. Напишите его так, чтобы любые динамические элементы могли быть приняты в качестве аргументов.
- в вашем AJAX-файле вызовите функцию, используя официальное событие DOM (onclick, onfocus, onblur, onload и т. д.) В зависимости от того, какие другие элементы находятся в вашем ответе, вы можете получить довольно умный о том, чтобы сделать его чувствовать себя бесшовным. Передайте свои динамические элементы в качестве аргументов.
- когда ваш элемент ответа заполняется и происходит событие, функция запускается.
пример
начать.php
<!DOCTYPE html> <html> <head> <title>Demo</title> <!-- these libraries are for the autocomplete() function --> <link rel="stylesheet" type="text/css" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/themes/ui-lightness/jquery-ui.css"> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script> <script type="text/javascript"> <!-- // this is the ajax call function editDemoText(ElementID,initialValue) { try { ajaxRequest = new XMLHttpRequest(); } catch (e) { try { ajaxRequest = new ActiveXObject("Msxml2.XMLHTTP"); } catch (e) { try { ajaxRequest = new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) { return false; }}} ajaxRequest.onreadystatechange = function() { if ( ajaxRequest.readyState == 4 ) { var ajaxDisplay = document.getElementById('responseDiv'); ajaxDisplay.innerHTML = ajaxRequest.responseText; } } var queryString = "?ElementID="+ElementID+"&initialValue="+initialValue; ajaxRequest.open("GET", "ajaxRequest.php"+queryString, true); ajaxRequest.send(null); } // this is the function we wanted to call in AJAX, // but we put it here instead with an argument (ElementID) function AttachAutocomplete(ElementID) { // this list is static, but can easily be pulled in from // a database using PHP. That would look something like this: /* * $list = ""; * $r = mysqli_query($mysqli_link, "SELECT element FROM table"); * while ( $row = mysqli_fetch_array($r) ) { * $list .= "\".str_replace('"','\"',$row['element'])."\","; * } * $list = rtrim($list,","); */ var availableIDs = ["Demo1","Demo2","Demo3","Demo4"]; $("#"+ElementID).autocomplete({ source: availableIDs }); } //--> </script> </head> <body> <!-- this is where the AJAX response sneaks in after DOM is loaded --> <!-- we're using an onclick event to trigger the initial AJAX call --> <div id="responseDiv"><a href="javascript:void(0);" onclick="editDemoText('EditableText','I am editable!');">I am editable!</a></div> </body> </html>ajaxRequest.php
<?php // for this application, onfocus works well because we wouldn't really // need the autocomplete populated until the user begins typing echo "<input type=\"text\" id=\"".$_GET['ElementID']."\" onfocus=\"AttachAutocomplete('".$_GET['ElementID']."');\" value=\"".$_GET['initialValue']."\" />\n"; ?>
Федерико Zancan это правильно, но вам не нужно давать вашему скрипту идентификатор и оценивать весь ваш скрипт. Просто оцените свое имя функции, и его можно вызвать.
чтобы достичь этого в нашем проекте, мы написали прокси-функцию для вызова функции, возвращаемой внутри ответа Ajax.
function FunctionProxy(functionName){ var func = eval(functionName); func(); }