web-dev-qa-db-fra.com

Comment faire en sorte que jQuery attende la fin d'un appel Ajax avant son retour?

J'ai une fonction côté serveur qui nécessite une connexion. Si l'utilisateur est connecté, la fonction retournera 1 en cas de succès. Sinon, la fonction retournera la page de connexion.

Je veux appeler la fonction en utilisant Ajax et jQuery. Ce que je fais est de soumettre la demande avec un lien ordinaire, avec une fonction de clic appliquée dessus. Si l'utilisateur n'est pas connecté ou si la fonction échoue, je souhaite que l'appel Ajax renvoie true, pour que le déclencheur href se déclenche.

Cependant, lorsque j'utilise le code suivant, la fonction se ferme avant que l'appel Ajax soit terminé.

Comment puis-je rediriger gracieusement l'utilisateur vers la page de connexion?

$(".my_link").click(
    function(){
    $.ajax({
        url: $(this).attr('href'),
        type: 'GET',
        cache: false,
        timeout: 30000,
        error: function(){
            return true;
        },
        success: function(msg){ 
            if (parseFloat(msg)){
                return false;
            } else {
                return true;
            }
        }
    });
});
219
Hobhouse

Si vous ne souhaitez pas que la fonction $.ajax() revienne immédiatement, définissez l'option async sur false:

$(".my_link").click(
    function(){
    $.ajax({
        url: $(this).attr('href'),
        type: 'GET',
        async: false,
        cache: false,
        timeout: 30000,
        error: function(){
            return true;
        },
        success: function(msg){ 
            if (parseFloat(msg)){
                return false;
            } else {
                return true;
            }
        }
    });
});

Mais je ferais remarquer que cela irait à l’encontre du principe d’AJAX. Vous devez également gérer la réponse dans les fonctions error et success. Ces fonctions ne seront appelées que lorsque la réponse sera reçue du serveur.

328
cgp

Je n'utilise pas $.ajax mais les fonctions $.post et $.get, donc si j'ai besoin d'attendre la réponse, j'utilise ceci:

$.ajaxSetup({async: false});
$.get("...");
38
MilMike

L'objet XMLHttpRequest sous-jacent (utilisé par jQuery pour effectuer la demande) prend en charge la propriété asynchrone. Réglez-le sur false. Comme

async: false
30
idrosid

Au lieu de définir async sur false, ce qui est généralement une mauvaise conception, vous pouvez envisager de bloquer l'interface utilisateur pendant que l'opération est en attente.

Ceci peut être parfaitement réalisé avec les promesses jQuery suivantes:

// same as $.ajax but settings can have a maskUI property
// if settings.maskUI==true, the UI will be blocked while ajax in progress
// if settings.maskUI is other than true, it's value will be used as the color value while bloking (i.e settings.maskUI='rgba(176,176,176,0.7)'
// in addition an hourglass is displayed while ajax in progress
function ajaxMaskUI(settings) {
    function maskPageOn(color) { // color can be ie. 'rgba(176,176,176,0.7)' or 'transparent'
        var div = $('#maskPageDiv');
        if (div.length === 0) {
            $(document.body).append('<div id="maskPageDiv" style="position:fixed;width:100%;height:100%;left:0;top:0;display:none"></div>'); // create it
            div = $('#maskPageDiv');
        }
        if (div.length !== 0) {
            div[0].style.zIndex = 2147483647;
            div[0].style.backgroundColor=color;
            div[0].style.display = 'inline';
        }
    }
    function maskPageOff() {
        var div = $('#maskPageDiv');
        if (div.length !== 0) {
            div[0].style.display = 'none';
            div[0].style.zIndex = 'auto';
        }
    }
    function hourglassOn() {
        if ($('style:contains("html.hourGlass")').length < 1) $('<style>').text('html.hourGlass, html.hourGlass * { cursor: wait !important; }').appendTo('head');
        $('html').addClass('hourGlass');
    }
    function hourglassOff() {
        $('html').removeClass('hourGlass');
    }

    if (settings.maskUI===true) settings.maskUI='transparent';

    if (!!settings.maskUI) {
        maskPageOn(settings.maskUI);
        hourglassOn();
    }

    var dfd = new $.Deferred();
    $.ajax(settings)
        .fail(function(jqXHR, textStatus, errorThrown) {
            if (!!settings.maskUI) {
                maskPageOff();
                hourglassOff();
            }
            dfd.reject(jqXHR, textStatus, errorThrown);
        }).done(function(data, textStatus, jqXHR) {
            if (!!settings.maskUI) {
                maskPageOff();
                hourglassOff();
            }
            dfd.resolve(data, textStatus, jqXHR);
        });

    return dfd.promise();
}

avec cela, vous pouvez maintenant faire:

ajaxMaskUI({
    url: url,
    maskUI: true // or try for example 'rgba(176,176,176,0.7)'
}).fail(function (jqXHR, textStatus, errorThrown) {
    console.log('error ' + textStatus);
}).done(function (data, textStatus, jqXHR) {
    console.log('success ' + JSON.stringify(data));
});

Et l'interface utilisateur bloquera jusqu'au retour de la commande ajax

voir jsfiddle

21
kofifus

Je pense que les choses seraient plus faciles si vous codiez votre fonction success pour charger la page appropriée au lieu de renvoyer true ou false.

Par exemple, au lieu de retourner true, vous pourriez faire:

window.location="appropriate page";

Ainsi, lorsque la fonction de succès est appelée, la page est redirigée.

11
samuelagm