Вызов функции JavaScript, возвращенной из ответа Ajax - PullRequest
67 голосов
/ 04 февраля 2009

У меня есть система, в которой я посылаю команду Ajax, которая возвращает блок скрипта с функцией в нем. После того, как эти данные правильно вставлены в DIV, я хочу иметь возможность вызывать эту функцию для выполнения необходимых действий.

Возможно ли это?

Ответы [ 17 ]

72 голосов
/ 04 февраля 2009

Я думаю, что правильно интерпретировать ваш вопрос в этой форме: «Хорошо, я уже закончил со всеми вещами Ajax; я просто хотел бы знать, может ли функция JavaScript мой обратный вызов Ajax, вставленный в DIV, вызываться в любое время из в этот момент, то есть я не хочу вызывать его контекстно для возврата обратного вызова ".

ОК, если вы имеете в виду что-то вроде этого, ответ «да», вы можете вызывать новый код к этому моменту в любое время во время сохранения страницы в браузере при следующих условиях:

1) Ваш код JavaScript, возвращаемый обратным вызовом Ajax, должен быть синтаксически ОК;
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 и т. П., Но учтите, что такое решение может вызвать дополнительные проблемы. особенно если ваши Ajax-вызовы должны повторяться, т. е. если контекст той же функции должен измениться, или в случае сохранения сохранности объявленной функции, поэтому, возможно, вам следует серьезно подумать об изменении своего дизайна на один из предложенных примеров в этом потоке.

Наконец, если я неправильно понял ваш вопрос, а вы говорите о контекстном вызове функции, когда ваш обратный вызов Ajax возвращается, то я чувствую, что предлагаю прототипный подход , описанный krosenvold , поскольку он является кросс-браузерным, протестирован и полностью функционален, и это может дать вам лучшую дорожную карту для будущих реализаций.

42 голосов
/ 09 апреля 2012

Примечание : eval () может быть легко использован неправильно, скажем, что запрос перехватывается третьей стороной и отправляет вам недоверенный код. Тогда с помощью eval () вы будете запускать этот ненадежный код. Обратитесь сюда за опасностями eval () .


Внутри возвращенного файла HTML / Ajax / JavaScript у вас будет тег JavaScript. Присвойте ему идентификатор, например runcript . Добавление идентификаторов в эти теги редко, но это необходимо для конкретной ссылки.

<script type="text/javascript" id="runscript">
    alert("running from main");
</script>

В главном окне затем вызовите функцию eval, оценив только этот НОВЫЙ блок кода JavaScript (в данном случае он называется runcript ):

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

И это работает, по крайней мере, в Internet Explorer 9 и Google Chrome.

9 голосов
/ 04 февраля 2009

Это вполне возможно, и для этого есть даже несколько вполне законных вариантов использования. Используя Prototype framework, это делается следующим образом.

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

См. документацию программы обновления Ajax. Опции находятся в наборе общих опций . Как обычно, есть некоторые предостережения относительно того, на что указывает «это», поэтому прочитайте мелкий шрифт.

Код JavaScript будет оцениваться при загрузке. Если содержимое содержит функцию myFunc(), Вы могли бы просто сказать myFunc() потом. Может быть следующим.

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

Проверяет, существует ли функция. Может быть, у кого-то есть лучший кросс-браузерный способ сделать это, который работает в Internet Explorer 6.

6 голосов
/ 04 февраля 2009

Это выглядит довольно странно для вашего кода - обычно имеет смысл вызывать ваши функции напрямую из файла .js, а затем получать данные только с помощью вызова Ajax.

Однако я считаю, что это должно работать, вызывая eval () в ответе - при условии, что это синтаксически правильный код JavaScript.

5 голосов
/ 04 февраля 2009

С jQuery я бы сделал это, используя getScript

3 голосов
/ 25 июня 2012

Я хотел бы добавить, что в jQuery есть функция eval, позволяющая вам оценивать код глобально, что должно избавить вас от любых контекстных проблем. Функция называется globalEval () , и она отлично работала для моих целей. Его документацию можно найти здесь .

Это пример кода, предоставленного документацией по API jQuery:

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

test();
// newVar === true

Эта функция чрезвычайно полезна, когда речь идет о динамической загрузке внешних сценариев, что вы, очевидно, пытались сделать.

3 голосов
/ 24 февраля 2011

Просто запомните, если вы создадите функцию как показано ниже через 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');
};

Но я также думаю, что вы не должны этого делать ...

Извините за любую ошибку здесь ...

2 голосов
/ 02 июля 2013

код стороны PHP Имя файла class.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()"/>

Теперь в нашем локальном script.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
                  }


        });
}
2 голосов
/ 07 июля 2011

Контрольный список для таких действий:

  1. возвращенный ответ Ajax - eval (ed).
  2. функции объявлены в форме func_name = function() {...}

Еще лучше, используйте фреймворки, которые обрабатывают это как в Prototype . У вас есть Ajax.updater.

1 голос
/ 27 июля 2016

Моя обычная функция вызова 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 и будут запускаться один за другим. Кажется, это работает очень хорошо для меня. Два последних параметра являются необязательными.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...