2009-09-16 13 views
23

Tengo un cuadro de diálogo jQuery que se abre y luego se realiza una llamada AJAX. Me gustaría hacerlo de forma que si el cuadro de diálogo está cerrado o se presiona el botón de cancelar, la llamada AJAX se cancela y no se llama a su función de devolución de llamada. Puedo pensar en algunas maneras de hacerlo con una variable de este modo:¿Cancelar una llamada jQuery AJAX antes de que regrese?

function doStuff(){ 
    var doCallback = true; 
    $('#dialog').dialog({ 
     title: 'Dialog Title', 
     modal: true, 
     buttons: { 
     Cancel: function() { 
      doCallback = false; 
      doSomethingElse(); 
     } 
     } 
    }); 
    $.get('url/url/url', function(data){ 
     if(doCallback){ 
     doTheSuccessThing(data); 
     } 
    }); 
    } 

Pero, de alguna manera se siente sucia para mí y que en realidad no detener la llamada AJAX de completar. ¿Existe una forma integrada de cancelar una llamada AJAX en curso?

+0

No es algo que haya intentado, pero el método get() devuelve la subyacente XMLHttpRequest, que puede ser abort() ed. ¿Eso ayudaría? – Andy

+0

posible duplicado de [Cancelación de jquery de solicitud de Ajax anterior] (http: // stackoverflow.com/questions/4342438/canceling-previous-ajax-request-jquery) – Phrogz

Respuesta

14

Ok, así que con sede fuera de la sugerencia de utilizar el objeto XmlHttpRequest devuelto por la función $ .get me ocurrió esto:

function doStuff(){ 
    var ajaxRequest = $.ajax({ 
         url : 'url/url/url', 
         type : "GET", 
         success : function(data){ 
          ajaxRequest = null; 
          doSuccessStuff(data); 
         } 
         }); 

    $('#dialog').dialog({ 
     title: 'Stuff Dialog', 
     bgiframe: true, 
     modal: true, 
     buttons: { 
     Cancel: function() { 
      if (ajaxRequest) 
      ajaxRequest.abort(); 
      doCancelStuff(); 
     } 
     } 
    }); 
    } 

Parece para trabajar y se siente más limpio para mí.

+3

no se olvide de comprobar que ajaxRequest sea nulo. debe restablecerlo también en el método de 'éxito' - entonces puede juzgar si hay una solicitud de ajax activa o no –

+0

'doSuccessStuff()' aún puede invocarse incluso después de abortar la solicitud. Vea mi respuesta a continuación para una técnica para protegerse de esto. – Phrogz

4

Parece que sí, aunque nunca lo he hecho.

$.get devuelve un objeto XmlHttpRequest, que tiene un método abort() que puede llamar. Tal vez intentar eso?

5

No hay método en jQuery, pero solo puede usar el objeto XmlHttpRequest devuelto de las funciones jQuery get/post/ajax.

Desde el jQuery blog:

// Perform a simple Ajax request 
var req = $.ajax({ 
    type: "GET", 
    url: "/user/list/", 
    success: function(data) { 
    // Do something with the data... 
    // Then remove the request. 
    req = null; 
    } 
}); 

// Wait for 5 seconds 
setTimeout(function(){ 
    // If the request is still running, abort it. 
    if (req) req.abort(); 
}, 5000); 
17

Cuando tengo una devolución de llamada que pueda alimentarse varias veces, pero yo quiero usar sólo la última, que utilicen el siguiente procedimiento:

var resultsXHR, resultsTimer, resultsId=0; 
$('input').keyup(function(){ 
    clearTimeout(resultsTimer);      // Remove any queued request 
    if (resultsXHR) resultsXHR.abort();    // Cancel request in progress 
    resultsTimer = setTimeout(function(){   // Record the queued request 
    var id = ++resultsId;       // Record the calling order 
    resultsXHR = $.get('/results',function(data){ // Capture request in progress 
     resultsXHR = null;       // This request is done 
     if (id!=resultsId) return;     // A later request is pending 
     // ... actually do stuff here ... 
    }); 
    },500);           // Wait 500ms after keyup 
}); 

El abort() por sí sola no es suficiente para evitar la devolución de llamada de éxito de siendo invocado; aún puede encontrar la ejecución de devolución de llamada aunque haya intentado cancelar la solicitud. Es por esto que es necesario utilizar el rastreador resultsId y hacer que su devolución de llamada se tramite si otra, más adelante, la retrollamada superpuesta está lista para funcionar.

Teniendo en cuenta lo común y engorroso que es esto, creo que es una buena idea envolverlo de una manera reutilizable que no requiera la creación de un triplete único de nombres de variables locales para cada uno que desee Mango:

(function($){ 
    $.fn.bindDelayedGet = function(event,delay,url,dataCallback,dataType,callback){ 
    var xhr, timer, ct=0; 
    return this.bind(event,function(){ 
     clearTimeout(timer); 
     if (xhr) xhr.abort(); 
     timer = setTimeout(function(){ 
     var id = ++ct; 
     xhr = $.get(url,dataCallback && dataCallback(),function(data){ 
      xhr = null; 
      if (id==ct) callback(data); 
     },dataType); 
     },delay); 
    }); 
    }; 
})(jQuery); 

// In action 
var inp = $('#myinput').bindDelayedGet('keyup',400,'/search', 
    function(){ return {term:inp.val()}; }, 
    'html', 
    function(html){ $('#searchResults').clear().append(html); } 
); 

puede encontrar el código anterior se discute en más detalle on my website.

+0

Me pregunto cómo puedo hacer esto en el contexto de Backbone. –

+0

El código en la parte superior funcionó perfectamente para mí –

0

Si pone un condicional en el script que ajax a donde con la condición que es verdadera usted saca su html, de lo contrario, no genera nada, entonces puede hacer simple si (html) marca la función de éxito de esta manera:

$.ajax({ 
     type: "GET", 
     url: "url.php", 
     data: "data="+data, 
     success: function(html) 
      { 
       if(html){ 
       $("#container").empty().html(html); 
       } 
     } 
}); 

en este ejemplo, url.php podría ser algo como esto:

$data = $_GET['data']; 

if($data=="whatever"){ 
    echo "<div>Hello</div>"; 
}else{} 

esto funcionó para mí. Sé que esta publicación es antigua, pero espero que ayude a alguien.

Cuestiones relacionadas