jQuery geri çağrı içine daha fazla parametre geçmek


255

JQuery geri arama işlevine daha fazla veri geçirmek için bir yolu var mı?

İki fonksiyonum var ve $.postörneğin AJAX çağrısının hem elde edilen verilerini hem de birkaç özel argümanı iletmek için geri çağırma istiyorum

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 çağrısından döndürülen sonucun yanı sıra kendi parametrelerimi geri aramaya da iletmek istiyorum.


14
JQuery.ajax (), 1.4 sürümünden ( jquery14.com/day-01/jquery-14 ) bu yana kullanımının bir örneğine bakınca bir bağlam ayarına sahip olduğunu belirtmek gerekir : stackoverflow.com/questions/5097191/ajax-context- seçenek /…
russau

AJAX tamamlandıktan sonra veri döndürme sorunum çözüldü ve sonra doSomething.
Onaiggac

Yanıtlar:


340

Çözüm, değişkenlerin kapanma yoluyla bağlanmasıdır.


Daha temel bir örnek olarak, burada bir geri arama işlevi alan ve çağıran bir örnek işlevin yanı sıra örnek bir geri arama işlevi verilmiştir:

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

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

Bu geri çağrıyı çağırır ve tek bir argüman sağlar. Şimdi ek bir argüman sunmak istersiniz, böylece geri aramayı kapatırsınız.

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

Veya daha basit bir şekilde ES6 Ok Fonksiyonlarını kullanarak :

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

Özel örneğinize gelince, .postişlevi jQuery'de kullanmadım, ancak belgelerin hızlı bir şekilde taranması, geri aramanın aşağıdaki imzalı bir işlev işaretçisi olması gerektiğini gösteriyor :

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

Bu nedenle çözümün şöyle olduğunu düşünüyorum:

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

Ne oluyor?

Son satırında, doSomething(extraStuff)bir çağrılan ve çağırma sonucu meydana gelir işlev işaretçisi .

Çünkü extraStuffbir argüman olarak geçilirse fonksiyonun doSomethingkapsamı içindedir doSomething.

Geri extraStuffdöndürülen anonim iç işlevinde ne zaman başvurulursa doSomething, dış işlevin extraStuffbağımsız değişkenine kapanarak bağlanır . Bu, doSomethinggeri döndükten sonra bile geçerlidir .

Yukarıdakileri test etmedim, ancak son 24 saat içinde çok benzer bir kod yazdım ve tarif ettiğim gibi çalışıyor.

Kişisel tercihinize / kodlama standartlarınıza bağlı olarak tek bir 'extraStuff' nesnesi yerine elbette birden fazla değişkeni iletebilirsiniz.


'Var doSomething =' nin amacı nedir? Bu sadece doSomething'i bir işlev olarak bildirmekten nasıl farklıdır (yani, işlev doSomething (...) {})
Dave Neeley

7
Bu doğru değil. Bu iki işlev bildirimi için farklı kapsam kuralları geçerlidir. JS çalışma zamanına (tarayıcıyı oku) bağlı olarak davranış çok farklıdır. Ayrıca Firebug'daki yığın izinde / kesme noktasında gösterilen işlev adını karşılaştırmayı deneyin.
Ihor Kaharlichenko

1
Ihor: İki bildirim stili arasındaki fark konusunda kesinlikle haklısın. İyi bir açıklama burada: stackoverflow.com/questions/336859/…
bradhouse

2
Örneğin özgüllüğü nedeniyle bunu daha genel sorunlara uygulamaya çalışan kullanıcılar için bunu takip etmek biraz zor olabilir. Bu soruyu yeni yayınlanan önerilen yinelenen bir kopyası olarak kapatılmasını önlemek için basitleştirilmiş bir örnek takip etmek biraz daha kolay hale getirmenin yanı sıra bir ok işlevi örneği ekledim. Düzenlemelerimin cevabınızın orijinal amacından çok saptığını veya başka herhangi bir şekilde uygunsuz olduğunu düşünüyorsanız, lütfen geri almaktan çekinmeyin.

4
bu cevabın 4. düzeltmesi meta
bjb568

82

Kullanırken doSomething(data, myDiv), aslında işlevi çağırır ve ona bir başvuru yapmazsınız.

doStomethingİşlevi doğrudan iletebilirsiniz, ancak doğru imzaya sahip olduğundan emin olmalısınız.

DoSomething ürününü olduğu gibi tutmak istiyorsanız, çağrısını anonim bir işlevle sarabilirsiniz.

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

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

Anonim işlev kodunun içinde, ekteki kapsamda tanımlanan değişkenleri kullanabilirsiniz. Javascript kapsam belirleme yöntemi bu şekilde çalışır.


9
Bu, netlik adına en iyi IMO çözümüdür. return function(...){...}İşlev içinde fazladan işlev yok doSomething. Burada aynı kavramın başka bir açık örneğini buldum: theelitist.net/…
William Denniss

4
Sanırım bununla ilgili bir sorun var. Ek verileriniz (bu durumda myDiv) geri arama tetiklenmeden önce değişirse, eski değeri değil yeni değeri alırsınız! Benim durumumda, bir dizideki öğelere ajax çağrıları ateşliyordum ve ilk başarılı () çağrı gerçekleştiğinde, ilk öğe son olduğunda başarılı olduğunu düşündüm! bradhouse'un yanıtı benim için çalıştı.
Chris

@Chris Evet, yakalanan değişkenler Javascript'te değiştirilebilir. Bu davranışı istemiyorsanız, değeri yakalamak için açık bir işlev oluşturmanız gerekir. En genel deyim, (function(myDiv){ ... })(myDiv)değişkeni yakalamak için kendi kendini yürüten bir işlevdir myDiv. Bu dolaylı olarak @ bradhouse yanıtında yapılır.
Vincent Robert

Bu ajax'ı n kez çağırırsanız, bu yöntem n farklı işlev oluşturur ve bunları başarılı geri aramaya aktarır. Bu performans açısından kötüdür. Bu @zeroasterisk'in cevabını kırmak iyidir.
yılmaz

@WilliamDenniss, IMHO ile hemfikirim, bu en iyi, basit ve net çözüm
sebasira

52

Aslında herkesin ses çıkarmasından daha kolaydır ... özellikle $.ajax({})de yardımcı sözdizimine karşı temel sözdizimini kullanırsanız .

Sadece geçmek key: value, herhangi bir nesneye yaptığınız gibi ayarlayabileceğiniz ajax isteği ... ne zaman, çifti (çünkü $(this)henüz bağlamı değişmedi, hala yukarıdaki bağlama çağrısı için bir tetik)

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

Bunun var ayarını yapmaktan daha iyi olmasının nedenlerinden biri var değişkeninin küresel olması ve bu nedenle üzerine yazılabilir olmasıdır ... ajax çağrılarını tetikleyebilecek 2 şeyiniz varsa, teorik olarak bunları ajax çağrısının yanıt verdiğinden daha hızlı tetikleyebilirsiniz ve birincisine yapılan ikinci çağrı için değere sahip olursunuz. Yukarıda bu yöntemi kullanmak bu olmazdı (ve kullanımı da oldukça basit).


3
tam da aradığım şey buydu. DataType'ı json olarak belirttiğinizde, sizin için otomatik olarak yanıtı çözümlediğini bilmiyordum. O güzel (:
Horoz

1
Bana geri çağırmak için ekstra params geçirmenin en iyi yolu gibi geliyor. Kimse bu yaklaşım ile bir dezavantaj görürse ilgilenir misiniz? En kolay ve en zarif. Teşekkürler!
Jan Zyka

" var küresel ve bu yüzden üzerine yazılamaz ". Yukarıdaki çözümden çok daha okunabilir bir işlev içinde bildirirseniz değil. Kapakları kullanmak daha temiz bir yaklaşımdır - cevabımı buraya bakın: stackoverflow.com/a/18570951/885464
Lorenzo Polidori

5
@LorenzoPolidori Kabul etmiyorum, ek parametre yaklaşımını çok daha okunabilir buluyorum.
Andrew Plummer

2
Bu kesinlikle mükemmel. Neden daha önce hiç görmedim. İhtiyacım yok closuresadece işe ihtiyacım var ve bu kesinlikle as, temiz, basit ve küresel değil.
Piotr Kula

21

Bugünün dünyasında daha temiz olan ve başka bir Stack Overflow cevabından alınan başka bir cevap var:

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

İşte orijinal soru ve cevap: jQuery NASIL YAPILIR ?? $ .ajax çağrısı için başarılı geri aramaya ek parametreler iletilsin mi?


8

Ayrıca aşağıdakine benzer bir şey deneyebilirsiniz:

function clicked() {

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

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

function doSomething(curData, curDiv) {

}

5

JavaScript'in bir kapanışını kullanabilirsiniz:

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

ve ne zaman yapabileceğiniz:

$.post("someurl.php",data,wrapper(var1, var2, etc...),"html");

3

Son gönderimde bir hata yaptım. Bu, geri çağrı işlevinde ek bağımsız değişkenin nasıl iletileceğine dair çalışan bir örnektir:

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

1
Yeni bir cevap eklemeden önce orijinal cevabınızı düzenlemeniz veya silmeniz gerekir.
Blazemonger

3

Hadi basit olalım! :)

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

2

.ajax()JQuery API ve kapanışlarını kullanarak zamanuyumsuz istekleri göndermek için daha genel bir çözüm ve geri çağrı işlevine ek parametreler iletmek için:

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

Benim için ve Javascript ile yeni iletişim kuran diğer yeni başlayanlar
için Closeure Solution, bunun biraz kafa karıştırıcı olduğunu düşünüyorum .

Bunu bulduğumda, jquery kullanarak her ajax geri aramasına istediğiniz kadar parametre kolayca iletebilirsiniz.

İşte iki kolay çözüm .

Birincisi, @zeroasterisk'in yukarıda bahsettiği örnek:

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

İkincisi XHR object , tüm ajax-istek-yanıt ömrü boyunca mevcut olanlara ekleyerek kendi tanımladığınız verileri geçirin .

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

Gördüğünüz gibi bu iki çözümün bir dezavantajı var: her seferinde yazmaktan biraz daha fazla kod yazmanız gerekiyor:

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

$ .Ajax hakkında daha fazla bilgi edinin: http://api.jquery.com/jquery.ajax/


1

Birisi hala buraya geliyorsa, bu benim görüşüm:

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

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

Burada ne olur, geri çağırma işlevine bağlandıktan sonra, işlev içinde kullanılabilir this.

Bu fikir React'in bindişlevselliği nasıl kullandığıyla ilgilidir .


1
$(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);
}

İkincil yol:

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

0

aslında, kodunuz çalışmıyor çünkü yazarken:

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

bir işlev çağrısını işlev başvurusu yerine üçüncü parametre olarak yerleştirirsiniz .


0

B01'in cevabına bir ek olarak , ikinci argümanı $.proxygenellikle thisreferansı korumak için kullanılır . İletilen ek argümanlar $.proxyişleve kısmen uygulanır ve verilerle önceden doldurulur. $.postGeri aramaya iletilen tüm bağımsız değişkenlerin sonunda uygulanacağını, bu nedenle doSomethingbağımsız değişken listesinin sonunda olması gerektiğini unutmayın:

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

Bu yaklaşım, birden çok bağımsız değişkenin geri aramaya bağlanmasına da izin verir:

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;
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.