jQuery передает больше параметров в обратный вызов - PullRequest
250 голосов
/ 02 июня 2009

Есть ли способ передать больше данных в функцию обратного вызова в jQuery?

У меня есть две функции, и я хочу, чтобы обратный вызов к $.post, например, передавал как результирующие данные вызова AJAX, так и несколько пользовательских аргументов

function clicked() {
    var myDiv = $("#my-div");
    // ERROR: Says data not defined
    $.post("someurl.php",someData,doSomething(data, myDiv),"json"); 
    // ERROR: Would pass in myDiv as curData (wrong)
    $.post("someurl.php",someData,doSomething(data, myDiv),"json"); 
}

function doSomething(curData, curDiv) {

}

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

Ответы [ 14 ]

335 голосов
/ 02 июня 2009

Решением является привязка переменных через замыкание.


В качестве более простого примера, здесь приведен пример функции, которая получает и вызывает функцию обратного вызова, а также пример функции обратного вызова:

function callbackReceiver(callback) {
    callback("Hello World");
}

function callback(value1, value2) {
    console.log(value1, value2);
}

Это вызывает обратный вызов и предоставляет один аргумент. Теперь вы хотите предоставить дополнительный аргумент, поэтому вы закрываете обратный вызов при закрытии.

callbackReceiver(callback);     // "Hello World", undefined
callbackReceiver(function(value) {
    callback(value, "Foo Bar"); // "Hello World", "Foo Bar"
});

Или, проще, Функции стрелки ES6 :

callbackReceiver(value => callback(value, "Foo Bar")); // "Hello World", "Foo Bar"

Что касается вашего конкретного примера, я не использовал функцию .post в jQuery, но быстрое сканирование документации показывает, что обратный вызов должен быть указателем на функцию со следующей подписью:

function callBack(data, textStatus, jqXHR) {};

Поэтому я думаю, что решение заключается в следующем:

var doSomething = function(extraStuff) {
    return function(data, textStatus, jqXHR) {
        // do something with extraStuff
    };
};

var clicked = function() {
    var extraStuff = {
        myParam1: 'foo',
        myParam2: 'bar'
    }; // an object / whatever extra params you wish to pass.

    $.post("someurl.php", someData, doSomething(extraStuff), "json");
};

Что происходит?

В последней строке doSomething(extraStuff) вызывается , вызывается , а результатом этого вызова является указатель на функцию .

Поскольку extraStuff передается в качестве аргумента doSomething, оно входит в область действия doSomething.

Когда ссылка extraStuff указана в возвращенной анонимной внутренней функции doSomething, она связана закрытием с аргументом extraStuff внешней функции. Это верно даже после возвращения doSomething.

Я не проверял вышеизложенное, но я написал очень похожий код за последние 24 часа, и он работает так, как я описал.

Конечно, вы можете передавать несколько переменных вместо одного объекта extraStuff в зависимости от ваших личных предпочтений / стандартов кодирования.

79 голосов
/ 02 июня 2009

При использовании doSomething(data, myDiv) вы фактически вызываете функцию и не ссылаетесь на нее.

Вы можете либо передать функцию doStomething напрямую, но вы должны убедиться, что она имеет правильную подпись.

Если вы хотите сохранить doSomething таким, какой он есть, вы можете обернуть его вызов в анонимную функцию.

function clicked() {
    var myDiv = $("#my-div");
    $.post("someurl.php",someData, function(data){ 
      doSomething(data, myDiv)
    },"json"); 
}

function doSomething(curData, curDiv) {
    ...
}

Внутри анонимного кода функции вы можете использовать переменные, определенные в прилагаемой области видимости. Так работает Javascript.

50 голосов
/ 09 марта 2012

На самом деле это проще, чем у всех, когда это звучит ... особенно, если вы используете базовый синтаксис $.ajax({}) против одной из вспомогательных функций.

Просто передайте пару key: value, как для любого объекта, при настройке запроса ajax ... (поскольку $(this) еще не изменил контекст, он все еще является триггером для вызова bind выше)

<script type="text/javascript">
$(".qty input").bind("keypress change", function() {
    $.ajax({
        url: "/order_items/change/"+$(this).attr("data-order-item-id")+"/qty:"+$(this).val()+"/returnas.json",
        type: "POST",
        dataType: "json",
        qty_input: $(this),
        anything_else_i_want_to_pass_in: "foo",
        success: function(json_data, textStatus, jqXHR) {
            /* here is the input, which triggered this AJAX request */
            console.log(this.qty_input);
            /* here is any other parameter you set when initializing the ajax method */
            console.log(this.anything_else_i_want_to_pass_in);
        }
    });
});
</script>

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

20 голосов
/ 08 сентября 2011

В современном мире есть другой ответ, который чище и взят из другого ответа переполнения стека:

function clicked()
{
    var myDiv = $( "#my-div" );

    $.post( "someurl.php", {"someData": someData}, $.proxy(doSomething, myDiv), "json" );
}

function doSomething( data )
{
    // this will be equal to myDiv now. Thanks to jQuery.proxy().
    var $myDiv = this;

    // doing stuff.
    ...
}

Вот оригинальный вопрос и ответ: JQuery КАК? передать дополнительные параметры для успешного обратного вызова для вызова $ .ajax?

7 голосов
/ 02 июня 2009

Вы также можете попробовать что-то вроде следующего:

function clicked() {

    var myDiv = $("#my-div");

    $.post("someurl.php",someData,function(data){
        doSomething(data, myDiv);
    },"json"); 
}

function doSomething(curData, curDiv) {

}
5 голосов
/ 02 июня 2009

Вы можете использовать закрытие JavaScript:

function wrapper( var1, var2,....) // put here your variables
{
  return function( data, status)
  {
     //Handle here results of call
  }
};

и когда вы можете сделать:

$.post("someurl.php",data,wrapper(var1, var2, etc...),"html");
3 голосов
/ 09 апреля 2013

Пойдем просто! :)

$.ajax({
    url: myUrl,
    context: $this, // $this == Current $element
    success: function(data) {
        $.proxy(publicMethods.update, this)(data); // this == Current $element
    }
});
3 голосов
/ 03 сентября 2010

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

function custom_func(p1,p2) {
    $.post(AJAX_FILE_PATH,{op:'dosomething',p1:p1},
        function(data){
            return function(){
                alert(data);
                alert(p2);
            }(data,p2)
        }
    );
    return false;
}
2 голосов
/ 02 сентября 2013

Более общее решение для отправки асинхронных запросов с использованием .ajax() jQuery API и замыканий для передачи дополнительных параметров в функцию обратного вызова:

function sendRequest(method, url, content, callback) {
    // additional data for the callback
    var request = {
        method: method,
        url: url
    };

    $.ajax({
        type: method,
        url: url,
        data: content
     }).done(function(data, status, xhr) {
        if (callback) callback(xhr.status, data, request);
     }).fail(function(xhr, status) {
        if (callback) callback(xhr.status, xhr.response, request);
     });
};
1 голос
/ 15 октября 2016

Если кто-то все еще приходит сюда, это мой дубль:

$('.selector').click(myCallbackFunction.bind({var1: 'hello', var2: 'world'}));

function myCallbackFunction(event) {
    var passedArg1 = this.var1,
        passedArg2 = this.var2
}

Что здесь происходит, после привязки к функции обратного вызова она будет доступна внутри функции как this.

Эта идея проистекает из того, как React использует функциональность bind.

...