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.
14 ответов
Решением является связывание переменных через замыкание.
В качестве более простого примера, вот пример функции, которая получает и вызывает функцию обратного вызова, а также пример функции обратного вызова:
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 в зависимости от ваших личных предпочтений / стандартов кодирования.
Когда используешь 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.
Это на самом деле проще, чем все делают это звучит... особенно если вы используете $.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>
Одна из причин, по которой это лучше, чем установка переменной, заключается в том, что переменная является глобальной и, следовательно, перезаписываемой... если у вас есть две вещи, которые могут инициировать вызовы ajax, вы можете теоретически запускать их быстрее, чем отвечает вызов ajax, и у вас будет значение для второго вызова, переданного в первый. При использовании вышеописанного метода этого не произойдет (и его тоже довольно просто использовать).
В сегодняшнем мире есть другой ответ, который чище и взят из другого ответа Stack Overflow:
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?
Вы также можете попробовать что-то вроде следующего:
function clicked() {
var myDiv = $("#my-div");
$.post("someurl.php",someData,function(data){
doSomething(data, myDiv);
},"json");
}
function doSomething(curData, curDiv) {
}
Вы можете использовать закрытие 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");
Я сделал ошибку в последнем моем посте. Это рабочий пример того, как передать дополнительный аргумент в функцию обратного вызова:
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;
}
Пойдем просто!:)
$.ajax({
url: myUrl,
context: $this, // $this == Current $element
success: function(data) {
$.proxy(publicMethods.update, this)(data); // this == Current $element
}
});
Если кто-то все еще приходит сюда, это мое мнение:
$('.selector').click(myCallbackFunction.bind({var1: 'hello', var2: 'world'}));
function myCallbackFunction(event) {
var passedArg1 = this.var1,
passedArg2 = this.var2
}
Что происходит здесь, после привязки к функции обратного вызова, она будет доступна внутри функции как this
,
Эта идея исходит из того, как React использует bind
функциональность.
Более общее решение для отправки асинхронных запросов с использованием .ajax()
API jQuery и замыкания для передачи дополнительных параметров в функцию обратного вызова:
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);
});
};
$(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 --
}
Для меня и других новичков, которые только что связались с 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's 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/
В качестве дополнения к ответу b01, второй аргумент $.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;
}
На самом деле, ваш код не работает, потому что когда вы пишете:
$.post("someurl.php",someData,doSomething(data, myDiv),"json");
Вы помещаете вызов функции в качестве третьего параметра, а не ссылки на функцию.