JQuery передает больше параметров в обратный вызов

Есть ли способ передать больше данных в функцию обратного вызова в 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.

Ответ 1

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


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

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 Arrow:

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" в зависимости от ваших личных стандартов предпочтения/кодирования.

Ответ 2

При использовании 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.

Ответ 3

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

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

<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>

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

Ответ 4

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

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?

Ответ 5

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

function clicked() {

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

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

function doSomething(curData, curDiv) {

}

Ответ 6

Вы можете использовать закрытие 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");

Ответ 7

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

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;
}

Ответ 8

Пусть идет просто!:)

$.ajax({
    url: myUrl,
    context: $this, // $this == Current $element
    success: function(data) {
        $.proxy(publicMethods.update, this)(data); // this == Current $element
    }
});

Ответ 9

Более общее решение для отправки асинхронных запросов с использованием .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);
     });
};

Ответ 10

Для меня и других новичков, которые только что связались с Javascript,
Я думаю, что Closeure Solution немного путается.

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

Вот два простых решения.

Первый, который упоминался выше @zeroasterisk, например:

var $items = $('.some_class');
$.each($items, function(key, item){
    var url = 'http://request_with_params' + $(item).html();
    $.ajax({
        selfDom     : $(item),
        selfData    : 'here is my self defined data',

        url         : url,
        dataType    : 'json',
        success     : function(data, code, jqXHR){
            // in $.ajax callbacks, 
            // [this] keyword references to the options you gived to $.ajax
            // if you had not specified the context of $.ajax callbacks.
            // see http://api.jquery.com/jquery.ajax/#jQuery-ajax-settings context
            var $item = this.selfDom;
            var selfdata = this.selfData;
            $item.html( selfdata );
            ...
        } 
    });
});

Во-вторых, передайте самоопределяемые данные, добавив их в XHR object который существует в течение всего срока службы ajax-request-response.

var $items = $('.some_class');
$.each($items, function(key, item){
    var url = 'http://request_with_params' + $(item).html();
    $.ajax({
        url         : url,
        dataType    : 'json',
        beforeSend  : function(XHR) {
            // 为了便于回调,把当前的 jquery对象集存入本次 XHR
            XHR.selfDom = $(item);
            XHR.selfData = 'here is my self defined data';
        },
        success     : function(data, code, jqXHR){
            // jqXHR is a superset of the browser native XHR object
            var $item = jqXHR.selfDom;
            var selfdata = jqXHR.selfData;
            $item.html( selfdata );
            ...
        } 
    });
});

Как вы можете видеть, эти два решения имеют недостаток: вам нужно писать немного больше кода каждый раз, чем просто писать:

$.get/post (url, data, successHandler);

Подробнее о $.ajax: http://api.jquery.com/jquery.ajax/

Ответ 11

$(document).on('click','[action=register]',function(){
    registerSocket(registerJSON(),registerDone,second($(this)));
});

function registerSocket(dataFn,doneFn,second){
                 $.ajax({
                       type:'POST',
                       url: "http://localhost:8080/store/public/register",
                       contentType: "application/json; charset=utf-8",
                       dataType: "json",
                       data:dataFn
                 }).done ([doneFn,second])
                   .fail(function(err){
                            console.log("AJAX failed: " + JSON.stringify(err, null, 2));
                        });
}

function registerDone(data){
    console.log(JSON.stringify(data));
}
function second(element){
    console.log(element);
}

Вторичный путь:

function socketWithParam(url,dataFn,doneFn,param){
  $.ajax({
    type:'POST',
    url:url,
    contentType: "application/json; charset=utf-8",
    headers: { 'Authorization': 'Bearer '+localStorage.getItem('jwt')},
    data:dataFn
    }).done(function(data){
      doneFn(data,param);
    })
    .fail(function(err,status,xhr){
    console.log("AJAX failed: " + JSON.stringify(err, null, 2));
    });
}

$(document).on('click','[order-btn]',function(){
  socketWithParam(url,fakeDataFn(),orderDetailDone,secondParam);
});

function orderDetailDone(data,param){
  -- to do something --
}

Ответ 12

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

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

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

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

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

Ответ 13

на самом деле, ваш код не работает, потому что когда вы пишете:

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

вы помещаете вызов функции как третий параметр, а не ссылку на функцию.

Ответ 14

В качестве добавления к b01 answer второй аргумент $.proxy часто используется для сохранения ссылки this. Дополнительные аргументы, переданные в $.proxy, частично применяются к функции, предварительно заполняя ее данными. Обратите внимание, что любые аргументы $.post, передаваемые обратному вызову, будут применены в конце, поэтому doSomething должен иметь те, которые находятся в конце списка своих аргументов:

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

function doSomething(curDiv, curData) {
    //"this" still refers to the same "this" as clicked()
    var serverResponse = curData;
}

Этот подход также позволяет привязать несколько аргументов к обратному вызову:

function clicked() {
    var myDiv = $("#my-div");
    var mySpan = $("#my-span");
    var isActive = true;
    var callback = $.proxy(doSomething, this, myDiv, mySpan, isActive);
    $.post("someurl.php",someData,callback,"json"); 
}

function doSomething(curDiv, curSpan, curIsActive, curData) {
    //"this" still refers to the same "this" as clicked()
    var serverResponse = curData;
}