Comment afficher le chargement de spinner dans jQuery?

412

Dans Prototype, je peux montrer une image "loading ..." avec ce code:

var myAjax = new Ajax.Request( url, {method: 'get', parameters: pars, 
onLoading: showLoad, onComplete: showResponse} );

function showLoad () {
    ...
}

Dans jQuery , je peux charger une page de serveur dans un élément avec ceci:

$('#message').load('index.php?pg=ajaxFlashcard');

mais comment attacher un spinner de chargement à cette commande comme je l'ai fait dans Prototype?

Edward Tanguay
la source

Réponses:

793

Il y a plusieurs façons. Ma façon préférée est d'attacher une fonction aux événements ajaxStart / Stop sur l'élément lui-même.

$('#loadingDiv')
    .hide()  // Hide it initially
    .ajaxStart(function() {
        $(this).show();
    })
    .ajaxStop(function() {
        $(this).hide();
    })
;

Les fonctions ajaxStart / Stop se déclenchent chaque fois que vous effectuez des appels Ajax.

Mise à jour : à partir de jQuery 1.8, la documentation indique que cela .ajaxStart/Stopne devrait être joint qu'à document. Cela transformerait l'extrait ci-dessus en:

var $loading = $('#loadingDiv').hide();
$(document)
  .ajaxStart(function () {
    $loading.show();
  })
  .ajaxStop(function () {
    $loading.hide();
  });
nickf
la source
48
C'est probablement trop global pour une simple charge dans un DIV.
montréaliste le
363
trop global? combien de messages différents "veuillez patienter" voulez-vous?
nickf
23
de cette façon, malheureusement, vous ne pouvez pas contrôler le chargement du positionnement des div au cas où vous ne voudriez pas simplement afficher une fenêtre de chargement modal, mais l'afficher près de l'élément en attendant que le contenu ajax soit chargé dans ...
glaz666
10
ajaxStart et ajaxStop sont des événements jQuery afin que vous puissiez les nommer : stackoverflow.com/questions/1191485/… docs.jquery.com/Namespaced_Events
David Xia
10
Si vous utilisez jQuery> = 1.9, attachez les événements ajaxStart et ajaxStop à $ (document). jquery.com/upgrade-guide/1.9/…
Domenic
213

Pour jQuery j'utilise

jQuery.ajaxSetup({
  beforeSend: function() {
     $('#loader').show();
  },
  complete: function(){
     $('#loader').hide();
  },
  success: function() {}
});
kr00lix
la source
13
fonctionne pour moi, le html devrait avoir quelque chose comme: <div id = 'loader'> <img src = "spinner.gif" /> </div>
yigal
7
Celui-ci était le plus propre pour moi. Au lieu d'ajaxSetup, j'ai placé beforeSend: et complete: à l'intérieur de l'instruction $ ajax ({....
kenswdev
4
Je ne sais pas ce que cela vaut, mais jQuery mentionne dans sa documentation que l'utilisation de .ajaxSetup () n'est pas recommandée. lien
pec
Notez qu'appelé beforeSendavant chaque appel, alors qu'il ajaxStartn'est déclenché que lorsque la première méthode ajax est appelée. De même pour ajaxStop, il est appelé lorsque le dernier appel ajax se termine. Si vous avez plusieurs demandes simultanées, l'extrait de cette réponse ne fonctionnera pas correctement.
nickf
Ne fonctionne pas pour moi si l'appel ajax expire (Firefox 28 pour Mac).
osa
48

Vous pouvez simplement utiliser la .ajaxfonction de jQuery et utiliser son option beforeSendet définir une fonction dans laquelle vous pouvez afficher quelque chose comme un div de chargeur et en cas de succès, vous pouvez masquer ce div de chargeur.

jQuery.ajax({
    type: "POST",
    url: 'YOU_URL_TO_WHICH_DATA_SEND',
    data:'YOUR_DATA_TO_SEND',
    beforeSend: function() {
        $("#loaderDiv").show();
    },
    success: function(data) {
        $("#loaderDiv").hide();
    }
});

Vous pouvez avoir n'importe quelle image Gif tournante. Voici un site Web qui est un excellent générateur de chargeur AJAX selon votre schéma de couleurs: http://ajaxload.info/

Chercheur
la source
16
Le successne sera pas appelé en cas d'erreur, mais "vous recevrez toujours un completerappel, même pour les demandes synchrones", selon jQuery Ajax Events .
LeeGee
23

Vous pouvez insérer l'image animée dans le DOM juste avant l'appel AJAX, et faire une fonction en ligne pour la supprimer ...

$("#myDiv").html('<img src="images/spinner.gif" alt="Wait" />');
$('#message').load('index.php?pg=ajaxFlashcard', null, function() {
  $("#myDiv").html('');
});

Cela garantira que votre animation démarre à la même image lors des demandes suivantes (si cela est important). Notez que les anciennes versions d'IE peuvent avoir des problèmes avec l'animation.

Bonne chance!

Josh Stodola
la source
13
Astuce: préchargez le spinner.gif dans un div avec l'affichage défini sur aucun. Sinon, vous pourriez obtenir un peu d'effet de spinner retardé pendant que le spinner télécharge toujours.
uriDium
bon conseil, beaucoup plus simple que d'utiliser le plugin de quelqu'un d'autre
Gordon Thompson
Agréable! mais cher, une chose de plus que je veux afficher spinner pendant 2 secondes, même la page a déjà été chargée.
Les deux FM
5
@BothFM Parce que les gens aiment attendre des choses ...?
Josh Stodola
21
$('#message').load('index.php?pg=ajaxFlashcard', null, showResponse);
showLoad();

function showResponse() {
    hideLoad();
    ...
}

http://docs.jquery.com/Ajax/load#urldatacallback

Brent
la source
Vous pourriez avoir des problèmes de timing là-bas, non?
Tim Büthe
2
@UltimateBrent Je pense que vous vous êtes trompé. Pourquoi showLoad () n'est pas un rappel? JavaScript chargera le contenu de manière asynchrone. showLoad () fonctionnera même avant le chargement du contenu si je suis correct.
Jaseem
2
@Jaseem J'utilise également une méthode similaire et elle repose en fait sur des appels asynchrones. Je placerais showLoad quelque part avant l'appel ajax, mais le but est d'afficher un spinner, de laisser JS démarrer l'appel et de tuer le spinner dans un rappel une fois l'AJAX terminé.
Nenotlep
17

Si vous utilisez, $.ajax()vous pouvez utiliser quelque chose comme ceci:

$.ajax({
        url: "destination url",
        success: sdialog,
        error: edialog,
        // shows the loader element before sending.
        beforeSend: function () { $("#imgSpinner1").show(); },
        // hides the loader after completion of request, whether successfull or failor.             
        complete: function () { $("#imgSpinner1").hide(); },             
        type: 'POST', dataType: 'json'
    });  
Amin Saqi
la source
11

Utilisez le plugin de chargement: http://plugins.jquery.com/project/loading

$.loading.onAjax({img:'loading.gif'});
Nathan Bubna
la source
10
Un plugin pour cette tâche simple? Ce n'est pas vraiment une bonne solution n'est-ce pas? Qui veut charger 100 scripts sur une page?
Jaseem
2
D'accord. Compressez et concaténez, si vous voulez de meilleures performances.
Nathan Bubna
9
Pas d'accord: séparez et modularisez, réutilisez le code, si vous voulez être en mesure de maintenir votre travail et que d'autres le fassent aussi. Quelles sont les chances que votre utilisateur ait une connexion aussi médiocre que son client ne peut pas charger un plugin ainsi que votre code?
LeeGee
@NathanBubna Le lien est mort
SpringLearner
"Quelles sont les chances que votre utilisateur ait une connexion aussi pauvre que son client ne peut pas charger un plugin ainsi que votre code?" Je dirais plutôt bien.
andrew oxenburgh
9

Variante: J'ai une icône avec id = "logo" en haut à gauche de la page principale; un gif spinner est ensuite superposé sur le dessus (avec transparence) lorsque ajax fonctionne.

jQuery.ajaxSetup({
  beforeSend: function() {
     $('#logo').css('background', 'url(images/ajax-loader.gif) no-repeat')
  },
  complete: function(){
     $('#logo').css('background', 'none')
  },
  success: function() {}
});
Paul
la source
9

J'ai fini par apporter deux modifications à la réponse d'origine .

  1. Depuis jQuery 1.8, ajaxStart et ajaxStop ne doivent être attachés qu'à document . Cela rend plus difficile de filtrer uniquement certaines des demandes ajax. Soo ...
  2. Le passage à ajaxSend et ajaxComplete permet de croiser la requête ajax actuelle avant d'afficher le spinner.

Voici le code après ces modifications:

$(document)
    .hide()  // hide it initially
    .ajaxSend(function(event, jqxhr, settings) {
        if (settings.url !== "ajax/request.php") return;
        $(".spinner").show();
    })
    .ajaxComplete(function(event, jqxhr, settings) {
        if (settings.url !== "ajax/request.php") return;
        $(".spinner").hide();
    })
Emil Stenström
la source
Belle solution de contournement. ajaxCompletesemble tirer prématurément lorsque les demandes de nouvelle tentative, donc je l' ai utilisé une combinaison de ajaxSendet ajaxStopil fonctionne très bien.
Mahn
@SchweizerSchoggi: Il y a d'autres sujets qui répondent à cette question, utilisez la recherche!
Emil Stenström
8

Je veux également contribuer à cette réponse. Je cherchais quelque chose de similaire dans jQuery et c'est ce que j'ai finalement utilisé.

J'ai obtenu mon spinner de chargement sur http://ajaxload.info/ . Ma solution est basée sur cette réponse simple sur http://christierney.com/2011/03/23/global-ajax-loading-spinners/ .

Fondamentalement, votre balisage HTML et CSS ressemblerait à ceci:

<style>
     #ajaxSpinnerImage {
          display: none;
     }
</style>

<div id="ajaxSpinnerContainer">
     <img src="~/Content/ajax-loader.gif" id="ajaxSpinnerImage" title="working..." />
</div>

Et puis votre code pour jQuery ressemblerait à ceci:

<script>
     $(document).ready(function () {
          $(document)
          .ajaxStart(function () {
               $("#ajaxSpinnerImage").show();
          })
          .ajaxStop(function () {
               $("#ajaxSpinnerImage").hide();
          });

          var owmAPI = "http://api.openweathermap.org/data/2.5/weather?q=London,uk&APPID=YourAppID";
          $.getJSON(owmAPI)
          .done(function (data) {
               alert(data.coord.lon);
          })
          .fail(function () {
               alert('error');
          });
     });
</script>

C'est aussi simple que ça :)

Brendan Vogt
la source
8

Vous pouvez simplement affecter une image de chargeur à la même balise sur laquelle vous chargerez plus tard du contenu à l'aide d'un appel Ajax:

$("#message").html('<span>Loading...</span>');

$('#message').load('index.php?pg=ajaxFlashcard');

Vous pouvez également remplacer la balise span par une balise image.

Umesh kumar
la source
1
Il sera difficile de gérer l'interface utilisateur de cette façon. Nous pouvons avoir besoin de styles complètement différents pour le texte de "chargement" et le message final. Nous pouvons utiliser la méthode de rappel mentionnée ci-dessus pour gérer ce problème
Jaseem
6

Outre la définition de valeurs par défaut globales pour les événements ajax, vous pouvez définir le comportement d'éléments spécifiques. Peut-être que changer de classe suffirait?

$('#myForm').ajaxSend( function() {
    $(this).addClass('loading');
});
$('#myForm').ajaxComplete( function(){
    $(this).removeClass('loading');
});

Exemple CSS, pour masquer #myForm avec un spinner:

.loading {
    display: block;
    background: url(spinner.gif) no-repeat center middle;
    width: 124px;
    height: 124px;
    margin: 0 auto;
}
/* Hide all the children of the 'loading' element */
.loading * {
    display: none;  
}
LeeGee
la source
1
Cela devrait être la réponse choisie à mon avis. Merci @LeeGee.
Nam G VU
Vraiment une excellente réponse
Raskolnikov
4

Notez que vous devez utiliser des appels asynchrones pour que les filateurs fonctionnent (au moins c'est ce qui a fait que le mien ne s'affichait qu'après l'appel ajax, puis s'est rapidement dissipé car l'appel était terminé et a retiré le fileur).

$.ajax({
        url: requestUrl,
        data: data,
        dataType: 'JSON',
        processData: false,
        type: requestMethod,
        async: true,                         <<<<<<------ set async to true
        accepts: 'application/json',
        contentType: 'application/json',
        success: function (restResponse) {
            // something here
        },
        error: function (restResponse) {
            // something here                
        }
    });
Shane Rowatt
la source
4
$('#loading-image').html('<img src="/images/ajax-loader.gif"> Sending...');

        $.ajax({
            url:  uri,
            cache: false,
            success: function(){
                $('#loading-image').html('');           
            },

           error:   function(jqXHR, textStatus, errorThrown) {
            var text =  "Error has occured when submitting the job: "+jqXHR.status+ " Contact IT dept";
           $('#loading-image').html('<span style="color:red">'+text +'  </span>');

            }
        });
Izabela Skibinska
la source
Le moyen le plus court serait d'insérer une balise d'image avec une image téléchargée sur ajaxload.info avec un fond transparent
Izabela Skibinska
2

J'ai utilisé ce qui suit avec jQuery UI Dialog. (Peut-être que cela fonctionne avec d'autres rappels ajax?)

$('<div><img src="/i/loading.gif" id="loading" /></div>').load('/ajax.html').dialog({
    height: 300,
    width: 600,
    title: 'Wait for it...'
});

Le contient un gif de chargement animé jusqu'à ce que son contenu soit remplacé à la fin de l'appel ajax.

Quinn Comendant
la source
2

C'est la meilleure façon pour moi:

jQuery :

$(document).ajaxStart(function() {
  $(".loading").show();
});

$(document).ajaxStop(function() {
  $(".loading").hide();
});

Café :

  $(document).ajaxStart ->
    $(".loading").show()

  $(document).ajaxStop ->
    $(".loading").hide()

Documents: ajaxStart , ajaxStop

Fred K
la source
D'accord, et vous pouvez l'utiliser avec le plugin mentionné dans cette réponse si vous voulez ...
Matt
2

Javascript

$.listen('click', '#captcha', function() {
    $('#captcha-block').html('<div id="loading" style="width: 70px; height: 40px; display: inline-block;" />');
    $.get("/captcha/new", null, function(data) {
        $('#captcha-block').html(data);
    }); 
    return false;
});

CSS

#loading { background: url(/image/loading.gif) no-repeat center; }
Peter Mortensen
la source
2

Il s'agit d'un plugin très simple et intelligent pour cet objectif spécifique: https://github.com/hekigan/is-loading

andcl
la source
Vraiment sympa! Surtout si vous jetez un œil aux démos ... Désactivez les éléments DOM, dans les balises, la superposition complète, la superposition des éléments ... il fournit tout ce dont vous avez besoin. Et vous pouvez facilement combiner la superposition complète avec cette réponse pour la faire fonctionner instantanément.
Matt
1

Je fais ça:

var preloaderdiv = '<div class="thumbs_preloader">Loading...</div>';
           $('#detail_thumbnails').html(preloaderdiv);
             $.ajax({
                        async:true,
                        url:'./Ajaxification/getRandomUser?top='+ $(sender).css('top') +'&lef='+ $(sender).css('left'),
                        success:function(data){
                            $('#detail_thumbnails').html(data);
                        }
             });

la source
1

Je pense que tu as raison. Cette méthode est trop globale ...

Cependant - c'est une bonne valeur par défaut lorsque votre appel AJAX n'a ​​aucun effet sur la page elle-même. (sauvegarde en arrière-plan par exemple). (vous pouvez toujours le désactiver pour un certain appel ajax en passant "global": false - voir la documentation sur jquery

Lorsque l'appel AJAX est destiné à actualiser une partie de la page, j'aime que mes images de "chargement" soient spécifiques à la section actualisée. Je voudrais voir quelle partie est rafraîchie.

Imaginez à quel point ce serait cool si vous pouviez simplement écrire quelque chose comme:

$("#component_to_refresh").ajax( { ... } ); 

Et cela montrerait un "chargement" sur cette section. Vous trouverez ci-dessous une fonction que j'ai écrite qui gère également l'affichage du "chargement" mais elle est spécifique à la zone que vous rafraîchissez en ajax.

Tout d'abord, laissez-moi vous montrer comment l'utiliser

<!-- assume you have this HTML and you would like to refresh 
      it / load the content with ajax -->

<span id="email" name="name" class="ajax-loading">
</span>

<!-- then you have the following javascript --> 

$(document).ready(function(){
     $("#email").ajax({'url':"/my/url", load:true, global:false});
 })

Et c'est la fonction - un début de base que vous pouvez améliorer comme vous le souhaitez. c'est très flexible.

jQuery.fn.ajax = function(options)
{
    var $this = $(this);
    debugger;
    function invokeFunc(func, arguments)
    {
        if ( typeof(func) == "function")
        {
            func( arguments ) ;
        }
    }

    function _think( obj, think )
    {
        if ( think )
        {
            obj.html('<div class="loading" style="background: url(/public/images/loading_1.gif) no-repeat; display:inline-block; width:70px; height:30px; padding-left:25px;"> Loading ... </div>');
        }
        else
        {
            obj.find(".loading").hide();
        }
    }

    function makeMeThink( think )
    {
        if ( $this.is(".ajax-loading") )
        {
            _think($this,think);
        }
        else
        {
            _think($this, think);
        }
    }

    options = $.extend({}, options); // make options not null - ridiculous, but still.
    // read more about ajax events
    var newoptions = $.extend({
        beforeSend: function()
        {
            invokeFunc(options.beforeSend, null);
            makeMeThink(true);
        },

        complete: function()
        {
            invokeFunc(options.complete);
            makeMeThink(false);
        },
        success:function(result)
        {
            invokeFunc(options.success);
            if ( options.load )
            {
                $this.html(result);
            }
        }

    }, options);

    $.ajax(newoptions);
};
guy mograbi
la source
1

Si vous prévoyez d'utiliser un chargeur à chaque fois que vous effectuez une demande de serveur, vous pouvez utiliser le modèle suivant.

 jTarget.ajaxloader(); // (re)start the loader
 $.post('/libs/jajaxloader/demo/service/service.php', function (content) {
     jTarget.append(content); // or do something with the content
 })
 .always(function () {
     jTarget.ajaxloader("stop");
 });

Ce code utilise notamment le plugin jajaxloader (que je viens de créer)

https://github.com/lingtalfi/JAjaxLoader/

lingue
la source
1

Mon code ajax ressemble à ceci, en effet, je viens de commenter async: false line et le spinner apparaît.

$.ajax({
        url: "@Url.Action("MyJsonAction", "Home")",
        type: "POST",
        dataType: "json",
        data: {parameter:variable},
        //async: false, 

        error: function () {
        },

        success: function (data) {
          if (Object.keys(data).length > 0) {
          //use data 
          }
          $('#ajaxspinner').hide();
        }
      });

Je montre le spinner dans une fonction avant le code ajax:

$("#MyDropDownID").change(function () {
        $('#ajaxspinner').show();

Pour Html, j'ai utilisé une classe impressionnante de polices:

<i id="ajaxspinner" class="fas fa-spinner fa-spin fa-3x fa-fw" style="display:none"></i>

J'espère que cela aide quelqu'un.

Jaggan_j
la source
0

Vous pouvez toujours utiliser le plugin Block UI jQuery qui fait tout pour vous, et il bloque même la page de toute entrée pendant le chargement de ajax. Dans le cas où le plugin ne semble pas fonctionner, vous pouvez lire sur la bonne façon de l'utiliser dans cette réponse. Vérifiez-le.

SamyCode
la source