it-swarm.com.de

jQuery übergibt weitere Parameter an Callback

Gibt es eine Möglichkeit, in jQuery mehr Daten an eine Rückruffunktion zu übergeben?

Ich habe zwei Funktionen und möchte den Rückruf an die $.post, um beispielsweise sowohl die resultierenden Daten des AJAX Aufrufs als auch einige benutzerdefinierte Argumente zu übergeben

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

}

Ich möchte in der Lage sein, meine eigenen Parameter an einen Rückruf sowie das vom AJAX - Aufruf zurückgegebene Ergebnis zu übergeben.

251
atp

Die Lösung ist die Bindung von Variablen durch Schließen.


Als einfacheres Beispiel sehen Sie hier eine Beispielfunktion, die eine Rückruffunktion empfängt und aufruft, sowie eine Beispielrückruffunktion:

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

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

Dies ruft den Rückruf auf und liefert ein einziges Argument. Jetzt möchten Sie ein zusätzliches Argument angeben, damit Sie den Rückruf zum Abschluss bringen.

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

Oder einfacher mit ES6-Pfeilfunktionen :

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

Was Ihr spezielles Beispiel betrifft, habe ich die Funktion .post In jQuery nicht verwendet, aber ein schneller Scan der Dokumentation schlägt vor, dass der Rückruf a sein sollte funktionszeiger mit folgender Unterschrift:

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

Daher denke ich, dass die Lösung wie folgt lautet:

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

Was ist los?

In der letzten Zeile steht doSomething(extraStuff) aufgerufen und das Ergebnis dieses Aufrufs ist a funktionszeiger.

Da extraStuff als Argument an doSomething übergeben wird, liegt es im Geltungsbereich der Funktion doSomething.

Wenn in der zurückgegebenen anonymen inneren Funktion von extraStuff auf doSomething verwiesen wird, wird diese durch Schließen an das Argument extraStuff der äußeren Funktion gebunden. Dies gilt auch nach der Rückkehr von doSomething.

Ich habe den obigen Code nicht getestet, aber ich habe in den letzten 24 Stunden einen sehr ähnlichen Code geschrieben und er funktioniert so, wie ich es beschrieben habe.

Sie können natürlich mehrere Variablen anstelle eines einzelnen 'extraStuff'-Objekts übergeben, abhängig von Ihren persönlichen Präferenzen/Codierungsstandards.

336
bradhouse

Wenn Sie doSomething(data, myDiv) verwenden, rufen Sie die Funktion tatsächlich auf und verweisen nicht darauf.

Sie können die Funktion doStomething entweder direkt übergeben, aber Sie müssen sicherstellen, dass sie die richtige Signatur hat.

Wenn Sie etwas so lassen möchten, wie es ist, können Sie den Aufruf in eine anonyme Funktion einbinden.

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

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

Innerhalb des anonymen Funktionscodes können Sie die im umschließenden Bereich definierten Variablen verwenden. So funktioniert Javascript Scoping.

80
Vincent Robert

Tatsächlich ist es einfacher, als alle es klingen zu lassen ... vor allem, wenn Sie die $.ajax({}) Basissyntax im Vergleich zu einer der Hilfsfunktionen verwenden.

Übergeben Sie das key: value - Paar einfach wie jedes andere Objekt, wenn Sie Ihre Ajax-Anfrage einrichten ... (weil $(this) den Kontext noch nicht geändert hat, ist es immer noch das Trigger für den Bind-Aufruf oben)

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

Einer der Gründe, warum dies besser ist als das Setzen der Variable, ist, dass die Variable global und als solche überschreibbar ist. Wenn Sie zwei Dinge haben, die Ajax-Aufrufe auslösen können, können Sie sie theoretisch schneller auslösen, als Ajax-Aufrufe antworten Der Wert für den zweiten Anruf wird an den ersten übergeben. Mit dieser Methode würde das nicht passieren (und es ist auch ziemlich einfach zu benutzen).

50
zeroasterisk

In der heutigen Welt gibt es eine andere Antwort, die sauberer ist und einer anderen Stapelüberlauf-Antwort entnommen wurde:

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

Hier ist die ursprüngliche Frage und Antwort: jQuery übergibt zusätzliche Parameter an den Erfolgs-Callback für den Aufruf von $ .ajax?

20
b01

Sie können auch Folgendes ausprobieren:

function clicked() {

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

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

function doSomething(curData, curDiv) {

}
7
Rohan Almeida

Sie können eine Schließung von JavaScript verwenden:

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

und wenn du kannst:

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

Lass uns einfach gehen! :)

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

Ich habe in meinem letzten Beitrag einen Fehler gemacht. Dies ist ein funktionierendes Beispiel für die Übergabe eines zusätzlichen Arguments in der Rückruffunktion:

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

Eine allgemeinere Lösung zum Senden von asynchronen Anforderungen mit der jQuery-API .ajax() und Closures, um zusätzliche Parameter an die Rückruffunktion zu übergeben:

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

Wenn noch jemand hierher kommt, ist dies meine Einstellung:

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

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

Was hier passiert, ist nach dem Binden an die Rückruffunktion in der Funktion als this verfügbar.

Diese Idee stammt davon, wie React die bind -Funktionalität verwendet.

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

Sekundärer Weg:

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

Für mich und andere Neulinge, die gerade mit Javascript kontaktiert haben,
Ich glaube, dass der Closeure Solution ist ein bisschen zu verwirrend.

Während ich das gefunden habe, können Sie mit jquery mühelos so viele Parameter übergeben, wie Sie möchten.

Hier sind zwei einfachere Lösungen .

Erstes, das @ zeroasterisk oben erwähnt hat, Beispiel:

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

Zweitens, übergeben Sie selbstdefinierte Daten, indem Sie sie in das XHR object, der während der gesamten Lebensdauer von Ajax-Request-Response vorhanden ist.

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

Wie Sie sehen, haben diese beiden Lösungen den Nachteil, dass Sie jedes Mal etwas mehr Code schreiben müssen als nur:

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

Lesen Sie mehr über $ .ajax: http://api.jquery.com/jquery.ajax/

1
lyfing

Als Ergänzung zu b01s Antwort wird häufig das zweite Argument von $.proxy Verwendet, um die this -Referenz beizubehalten. Zusätzliche Argumente, die an $.proxy Übergeben werden, werden teilweise auf die Funktion angewendet und mit Daten vorab gefüllt. Beachten Sie, dass alle Argumente, die $.post An den Rückruf übergeben wird, am Ende angewendet werden. Daher sollten die Argumente in doSomething am Ende der Argumentliste stehen:

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

Mit diesem Ansatz können auch mehrere Argumente an den Rückruf gebunden werden:

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

tatsächlich funktioniert Ihr Code nicht, wenn Sie schreiben:

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

sie platzieren ein Funktionsaufruf als dritten Parameter und nicht ein Funktionsreferenz.

0
jrharshath