Tampilkan GIF spinner selama permintaan $ http di AngularJS?

234

Saya menggunakan $httplayanan AngularJS untuk membuat permintaan Ajax.

Bagaimana GIF pemintal (atau jenis indikator sibuk lainnya) ditampilkan saat permintaan Ajax dijalankan?

Saya tidak melihat sesuatu seperti ajaxstarteventdalam dokumentasi AngularJS.

Ajay Beniwal
sumber
2
Jika Anda menginginkan pemintal sederhana berdasarkan HTTP Interceptors, saya memiliki modul sudut untuk itu. Ini menggunakan pemintal Identified Sham yang populer. Lihatlah: github.com/harinair/angular-sham-spinner
Hari Gangadharan
1
Saya menulis sebuah plugin angular-httpshooter , ia merilis sebuah acara dengan data konfigurasi sesaat sebelum pemotretan panggilan dan melepaskan yang lain tepat setelah menerima resposne, Anda dapat menulis pemuat global yang menangkap peristiwa tersebut
Siddharth

Jawaban:

88

Berikut ini mantra terakhir AngularJS:

angular.module('SharedServices', [])
    .config(function ($httpProvider) {
        $httpProvider.responseInterceptors.push('myHttpInterceptor');
        var spinnerFunction = function (data, headersGetter) {
            // todo start the spinner here
            //alert('start spinner');
            $('#mydiv').show();
            return data;
        };
        $httpProvider.defaults.transformRequest.push(spinnerFunction);
    })
// register the interceptor as a service, intercepts ALL angular ajax http calls
    .factory('myHttpInterceptor', function ($q, $window) {
        return function (promise) {
            return promise.then(function (response) {
                // do something on success
                // todo hide the spinner
                //alert('stop spinner');
                $('#mydiv').hide();
                return response;

            }, function (response) {
                // do something on error
                // todo hide the spinner
                //alert('stop spinner');
                $('#mydiv').hide();
                return $q.reject(response);
            });
        };
    });

//regular angular initialization continued below....
angular.module('myApp', [ 'myApp.directives', 'SharedServices']).
//.......

Berikut ini sisanya (HTML / CSS) .... menggunakan

$('#mydiv').show(); 
$('#mydiv').hide(); 

untuk beralih. CATATAN: di atas digunakan dalam modul sudut di awal posting

#mydiv {  
    position:absolute;
    top:0;
    left:0;
    width:100%;
    height:100%;
    z-index:1000;
    background-color:grey;
    opacity: .8;
 }

.ajax-loader {
    position: absolute;
    left: 50%;
    top: 50%;
    margin-left: -32px; /* -1 * image width / 2 */
    margin-top: -32px;  /* -1 * image height / 2 */
    display: block;     
}

<div id="mydiv">
    <img src="lib/jQuery/images/ajax-loader.gif" class="ajax-loader"/>
</div>
banteng
sumber
19
Perhatikan bahwa Anda dapat menggunakan angular.element('#mydiv').show()sebagai gantinya$('#mydiv').show()
JMaylin
8
ini tidak berfungsi jika halaman Anda membuat beberapa permintaan ajax. Ini akan menyembunyikan pemuatan gif setelah permintaan pertama berakhir.
Meeker
38
Menurut praktik terbaik AngularJS '(yang melanggar solusi yang diterima) Anda tidak boleh memodifikasi DOM di luar arahan. Pertimbangkan untuk meminta pertunjukkan / sembunyikan pada elemen dari dalam arahan.
Mariusz
7
Saya tidak yakin saya cukup tahu untuk berkomentar ... Tapi bukankah cara yang tepat untuk melakukan ini adalah menggunakan ng-classarahan alih-alih menggunakan JQuery untuk menampilkan dan menyembunyikan elemen?
James Heald
2
@JamesHeald benar .. Anda seharusnya tidak perlu menggunakan jQuery untuk manipulasi dom di Angular. Lihat: ng-class, ng-if, ng-hide, ng-show, dll. Ada arahan untuk hampir semua yang Anda butuhkan.
jKlaus
471

Ini sangat tergantung pada kasus penggunaan khusus Anda, tetapi cara sederhana akan mengikuti pola seperti ini:

.controller('MainCtrl', function ( $scope, myService ) {
  $scope.loading = true;
  myService.get().then( function ( response ) {
    $scope.items = response.data;
  }, function ( response ) {
    // TODO: handle the error somehow
  }).finally(function() {
    // called no matter success or failure
    $scope.loading = false;
  });
});

Dan kemudian bereaksi padanya di templat Anda:

<div class="spinner" ng-show="loading"></div>
<div ng-repeat="item in items>{{item.name}}</div>
Josh David Miller
sumber
223
Jika Anda memiliki beberapa permintaan ajax secara bersamaan, Anda dapat mendeklarasikan loadingsebagai integer $scope.loading = 0;, ketika permintaan mulai Anda lakukan $scope.loading++;, dan ketika itu berakhir Anda lakukan $scope.loading--;. Dan tidak ada yang berubah dalam template. Jadi pemintal ditampilkan ketika setidaknya ada satu permintaan sedang berlangsung, dan disembunyikan sepanjang waktu
JMaylin
16
Anda mungkin harus mengatur pemuatan ke false dalam fungsi fallback kesalahan juga.
sebnukem
3
@sebnukem Benar kamu. Ini adalah contoh tingkat tinggi, tapi saya tetap melanjutkan dan menambahkannya untuk kejelasan. Terima kasih untuk umpan baliknya!
Josh David Miller
1
@JMaylin - Anda dapat menggunakan $ watch pada $ scope.loading untuk melakukan hal-hal lain
Jason
5
Cara yang lebih bersih, daripada memasukkan $scope.loading = falsekeberhasilan dan panggilan balik yang gagal, adalah dengan memasukkannya ke dalam .finally(). Itu akan terlihat seperti:mySvc.get().then(success, fail).finally(function() { $scope.loading = false; });
Tom
44

Ini versi menggunakan directivedan ng-hide.

Ini akan menampilkan loader selama semua panggilan melalui layanan sudut $http.

Dalam templat:

<div class="loader" data-loading></div>

pengarahan:

angular.module('app')
  .directive('loading', ['$http', function ($http) {
    return {
      restrict: 'A',
      link: function (scope, element, attrs) {
        scope.isLoading = function () {
          return $http.pendingRequests.length > 0;
        };
        scope.$watch(scope.isLoading, function (value) {
          if (value) {
            element.removeClass('ng-hide');
          } else {
            element.addClass('ng-hide');
          }
        });
      }
    };
}]);

dengan menggunakan ng-hidekelas pada elemen, Anda dapat menghindari jquery.


Kustomisasi: tambahkan interceptor

Jika Anda membuat pemuatan-interseptor, Anda dapat menampilkan / menyembunyikan loader berdasarkan suatu kondisi.

pengarahan:

var loadingDirective = function ($rootScope) {
  return function ($scope, element, attrs) {
      $scope.$on("loader_show", function () {
          return element.removeClass('ng-hide');
      });
      return $scope.$on("loader_hide", function () {
          return element.addClass('ng-hide');
      });
  };
};

pencegat:

  • misalnya: jangan tampilkan spinnerkapanresponse.background === true;
  • Mencegat requestdan / atau responseuntuk mengatur $rootScope.$broadcast("loader_show");atau$rootScope.$broadcast("loader_hide");

info lebih lanjut tentang menulis interseptor

punkrockpolly
sumber
@ punkrockpolly Dalam skenario spesifik saya, saya memiliki dua komponen individu yang memanggil layanan. Tapi ini hanya berfungsi untuk salah satunya, Haruskah saya melewati parameter atau sesuatu untuk membuat ini dapat digunakan kembali?
RicardoGonzales
@razorblade itu akan berputar kapan saja Anda melakukan panggilan melalui $httplayanan apa pun.
punkrockpolly
31

Jika Anda menggunakan ngResource, atribut $ resolved dari suatu objek berguna untuk loader:

Untuk sumber daya sebagai berikut:

var User = $resource('/user/:id', {id:'@id'});
var user = User.get({id: 1})

Anda bisa menautkan loader ke atribut $ resolved dari objek resource:

<div ng-hide="user.$resolved">Loading ...</div>
Alexander Sweeney
sumber
13

Baru saja menemukan angular-busyarahan yang menunjukkan loader sedikit tergantung pada beberapa panggilan async.

Misalnya, jika Anda harus membuat GET, referensi janji di Anda $scope,

$scope.req = $http.get('http://google.fr');

dan menyebutnya seperti ini:

<div cg-busy="req"></div>

Ini dia GitHub.

Anda juga dapat menginstalnya menggunakan bower(jangan lupa untuk memperbarui dependensi proyek Anda):

bower install angular-busy --save
Balthazar
sumber
Saya tidak dapat menemukan cara "menonaktifkan beberapa elemen" dalam dokumentasi. Bisakah Anda menjelaskan caranya? Misalnya, saya ingin menonaktifkan tombol saat pemintal ditampilkan.
c4k
sudut-sibuk hanya memakai elemen Anda topeng, saya tidak berpikir Anda dapat menonaktifkan tombol seperti yang ingin Anda lakukan, tetapi Anda dapat mengatur latar belakang di atasnya dengan template kosong untuk memberikan kesan ini. Saya bukan penutur asli, maaf untuk kebingungan :)
Balthazar
Oke, saya mengedit jawaban Anda untuk mencegah orang lain mengalami kebingungan yang sama. Bahasa Prancis yang berbahasa Inggris ke bahasa Prancis yang lain selalu membingungkan :)
c4k
5

Jika Anda membungkus panggilan api Anda dalam layanan / pabrik, maka Anda dapat melacak penghitung pemuatan di sana (per jawaban dan saran simultan yang sangat baik oleh @Jaylin), dan merujuk penghitung pemuatan melalui arahan. Atau kombinasi keduanya.

WRAPPER API

yourModule
    .factory('yourApi', ['$http', function ($http) {
        var api = {}

        //#region ------------ spinner -------------

        // ajax loading counter
        api._loading = 0;

        /**
         * Toggle check
         */
        api.isOn = function () { return api._loading > 0; }

        /**
         * Based on a configuration setting to ignore the loading spinner, update the loading counter
         * (for multiple ajax calls at one time)
         */
        api.spinner = function(delta, config) {
            // if we haven't been told to ignore the spinner, change the loading counter
            // so we can show/hide the spinner

            if (NG.isUndefined(config.spin) || config.spin) api._loading += delta;

            // don't let runaway triggers break stuff...
            if (api._loading < 0) api._loading = 0;

            console.log('spinner:', api._loading, delta);
        }
        /**
         * Track an ajax load begin, if not specifically disallowed by request configuration
         */
        api.loadBegin = function(config) {
            api.spinner(1, config);
        }
        /**
         * Track an ajax load end, if not specifically disallowed by request configuration
         */
        api.loadEnd = function (config) {
            api.spinner(-1, config);
        }

        //#endregion ------------ spinner -------------

        var baseConfig = {
            method: 'post'
            // don't need to declare `spin` here
        }

        /**
         * $http wrapper to standardize all api calls
         * @param args stuff sent to request
         * @param config $http configuration, such as url, methods, etc
         */
        var callWrapper = function(args, config) {
            var p = angular.extend(baseConfig, config); // override defaults

            // fix for 'get' vs 'post' param attachment
            if (!angular.isUndefined(args)) p[p.method == 'get' ? 'params' : 'data'] = args;

            // trigger the spinner
            api.loadBegin(p);

            // make the call, and turn of the spinner on completion
            // note: may want to use `then`/`catch` instead since `finally` has delayed completion if down-chain returns more promises
            return $http(p)['finally'](function(response) {
                api.loadEnd(response.config);
                return response;
            });
        }

        api.DoSomething = function(args) {
            // yes spinner
            return callWrapper(args, { cache: true });
        }
        api.DoSomethingInBackground = function(args) {
            // no spinner
            return callWrapper(args, { cache: true, spin: false });
        }

        // expose
        return api;
    });

ARAH PEMINTIP

(function (NG) {
    var loaderTemplate = '<div class="ui active dimmer" data-ng-show="hasSpinner()"><div class="ui large loader"></div></div>';

    /**
     * Show/Hide spinner with ajax
     */
    function spinnerDirective($compile, api) {
        return {
            restrict: 'EA',
            link: function (scope, element) {
                // listen for api trigger
                scope.hasSpinner = api.isOn;

                // attach spinner html
                var spin = NG.element(loaderTemplate);
                $compile(spin)(scope); // bind+parse
                element.append(spin);
            }
        }
    }

    NG.module('yourModule')
        .directive('yourApiSpinner', ['$compile', 'yourApi', spinnerDirective]);
})(angular);

PEMAKAIAN

<div ng-controller="myCtrl" your-api-spinner> ... </div>
drzaus
sumber
5

Untuk pemuatan dan model halaman, cara termudah adalah dengan menggunakan ng-showarahan dan menggunakan salah satu variabel data lingkup. Sesuatu seperti:

ng-show="angular.isUndefined(scope.data.someObject)".

Di sini, sementara someObjecttidak terdefinisi, pemintal akan ditampilkan. Setelah layanan kembali dengan data dan someObjectdiisi, pemintal akan kembali ke status tersembunyi.

Arnold.Krumins
sumber
3

Ini adalah cara termudah untuk menambahkan pemintal, saya kira: -

Anda dapat menggunakan ng-show dengan tag div dari salah satu pemintal cantik ini http://tobiasahlin.com/spinkit/ {{Ini bukan halaman saya}}

dan kemudian Anda bisa menggunakan logika semacam ini

//ajax start
    $scope.finderloader=true;
    
          $http({
    method :"POST",
    url : "your URL",
  data: { //your data
     
     }
  }).then(function mySucces(response) {
    $scope.finderloader=false;
      $scope.search=false;          
    $scope.myData =response.data.records;
  });
     
    //ajax end 
    
<div ng-show="finderloader" class=spinner></div>
//add this in your HTML at right place

ashish malgawa
sumber
3
Based on Josh David Miller response:

  <body>
  <header>
  </header>
<div class="spinner" ng-show="loading">
  <div class="loader" ></div>
</div>

<div ng-view=""></div>

<footer>
</footer>

</body>

Tambahkan css ini:

    .loader {
  border: 16px solid #f3f3f3;
  border-radius: 50%;
  border-top: 16px solid #3498db;
  border-bottom : 16px solid black;
  width: 80px;
  height: 80px;
  -webkit-animation: spin 2s linear infinite;
  animation: spin 2s linear infinite;
  position: absolute;
  top: 45%;
  left: 45%;
}

@-webkit-keyframes spin {
  0% { -webkit-transform: rotate(0deg); }
  100% { -webkit-transform: rotate(360deg); }
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}


.spinner{
  width: 100%;
height: 100%;
z-index: 10000;
position: absolute;
top: 0;
left: 0;
margin: 0 auto;
text-align: center;
vertical-align: middle;
background: white;
opacity: 0.6;
}

Dan hanya di sudut Anda tambahkan:

$ rootScope.loading = false; $ rootScope.loading = true; -> ketika $ http.get berakhir.

cabaji99
sumber
2

Membagikan versi saya tentang jawaban hebat dari @bulltorious, diperbarui untuk bangunan bersudut yang lebih baru (saya menggunakan versi 1.5.8 dengan kode ini), dan juga memasukkan gagasan @ JMaylin tentang menggunakan penghitung agar kuat untuk beberapa permintaan simultan, dan pilihan untuk melewatkan menampilkan animasi untuk permintaan yang membutuhkan waktu kurang dari beberapa milidetik minimum:

var app = angular.module('myApp');
var BUSY_DELAY = 1000; // Will not show loading graphic until 1000ms have passed and we are still waiting for responses.

app.config(function ($httpProvider) {
  $httpProvider.interceptors.push('busyHttpInterceptor');
})
  .factory('busyHttpInterceptor', ['$q', '$timeout', function ($q, $timeout) {
    var counter = 0;
    return {
      request: function (config) {
        counter += 1;
        $timeout(
          function () {
            if (counter !== 0) {
              angular.element('#busy-overlay').show();
            }
          },
          BUSY_DELAY);
        return config;
      },
      response: function (response) {
        counter -= 1;
        if (counter === 0) {
          angular.element('#busy-overlay').hide();
        }
        return response;
      },
      requestError: function (rejection) {
        counter -= 1;
        if (counter === 0) {
          angular.element('#busy-overlay').hide();
        }
        return rejection;
      },
      responseError: function (rejection) {
        counter -= 1;
        if (counter === 0) {
          angular.element('#busy-overlay').hide();
        }
        return rejection;
      }
    }
  }]);
qwwqwwq
sumber
2

Anda dapat menggunakan pencegat sudut untuk mengelola panggilan permintaan http

  <div class="loader">
    <div id="loader"></div>
  </div>

<script>
    var app = angular.module("myApp", []);

    app.factory('httpRequestInterceptor', ['$rootScope', '$location', function ($rootScope, $location) {
        return {
            request: function ($config) {
                $('.loader').show();
                return $config;
            },
            response: function ($config) {
                $('.loader').hide();
                return $config;
            },
            responseError: function (response) {
                return response;
            }
        };
    }]);

    app.config(['$stateProvider', '$urlRouterProvider', '$httpProvider',
        function ($stateProvider, $urlRouterProvider, $httpProvider) {
            $httpProvider.interceptors.push('httpRequestInterceptor');
        }]);

</script>

https://stackoverflow.com/a/49632155/4976786

Om Sharma
sumber
2

Cara sederhana tanpa pencegat atau jQuery

Ini adalah cara sederhana untuk menunjukkan pemintal yang tidak memerlukan perpustakaan pihak ketiga, pencegat, atau jQuery.

Di controller, atur dan reset bendera.

function starting() {
    //ADD SPINNER
    vm.starting = true;
    $http.get(url)
      .then(function onSuccess(response) {
        vm.data = response.data;
    }).catch(function onReject(errorResponse) {
        console.log(errorResponse.status);
    }).finally(function() {
        //REMOVE SPINNER
        vm.starting = false;
    });
};

Di HTML, gunakan bendera:

<div ng-show="vm.starting">
    <img ng-src="spinnerURL" />
</div>

<div ng-hide="vm.starting">
    <p>{{vm.data}}</p>
</div>

The vm.startingbendera diatur trueketika XHR dimulai dan dibersihkan ketika selesai XHR.

georgeawg
sumber
1

Ini bekerja dengan baik untuk saya:

HTML:

  <div id="loader" class="ng-hide" ng-show="req.$$state.pending">
    <img class="ajax-loader" 
         width="200" 
         height="200" 
         src="/images/spinner.gif" />
  </div>

Sudut:

  $scope.req = $http.get("/admin/view/"+id).success(function(data) {          
      $scope.data = data;
  });

Sementara janji yang dikembalikan dari $ http sedang menunggu, ng-show akan mengevaluasinya sebagai "benar". Ini secara otomatis diperbarui setelah janji terselesaikan ... yang persis seperti yang kita inginkan.

lembab
sumber
Ini bukan cara yang dinamis untuk melakukan itu.
Umair Hamid
Bisakah Anda jelaskan mengapa Anda percaya ini bukan cara yang dinamis untuk mencapai tujuan ini. Ini akan membantu orang lain membaca postingan ini. Terima kasih.
dank
Saya memiliki beberapa permintaan dalam aplikasi saya. $ scope.req hanya akan berfungsi untuk satu permintaan. Saat permintaan khusus ini pemuat lengkap akan bersembunyi dan tidak akan menunggu untuk menyelesaikan permintaan lainnya. Cara terbaik untuk mencapai ini adalah dengan menggunakan pencegat.
Umair Hamid
1

Digunakan intersepter berikut untuk menampilkan bilah pemuatan atas permintaan http

'use strict';
appServices.factory('authInterceptorService', ['$q', '$location', 'localStorage','$injector','$timeout', function ($q, $location, localStorage, $injector,$timeout) {

var authInterceptorServiceFactory = {};
var requestInitiated;

//start loading bar
var _startLoading = function () {
   console.log("error start loading");
   $injector.get("$ionicLoading").show();

}

//stop loading bar
var _stopLoading = function () {
    $injector.get("$ionicLoading").hide();
}

//request initiated
var _request = function (config) {
     requestInitiated = true;
    _startLoading();
    config.headers = config.headers || {};
    var authDataInitial = localStorage.get('authorizationData');
    if (authDataInitial && authDataInitial.length > 2) {
        var authData = JSON.parse(authDataInitial);
        if (authData) {
            config.headers.Authorization = 'Bearer ' + authData.token;
        }
    }
    return config;
}

//request responce error
var _responseError = function (rejection) {
   _stopLoading();
    if (rejection.status === 401) {
        $location.path('/login');
    }
    return $q.reject(rejection);
}

//request error
var _requestError = function (err) {
   _stopLoading();
   console.log('Request Error logging via interceptor');
   return err;
}

//request responce
var _response = function(response) {
    requestInitiated = false;

   // Show delay of 300ms so the popup will not appear for multiple http request
   $timeout(function() {

        if(requestInitiated) return;
        _stopLoading();
        console.log('Response received with interceptor');

    },300);

return response;
}



authInterceptorServiceFactory.request = _request;
authInterceptorServiceFactory.responseError = _responseError;
authInterceptorServiceFactory.requestError = _requestError;
authInterceptorServiceFactory.response = _response;

return authInterceptorServiceFactory;
}]);
Dinesh Vaitage
sumber
0
.factory('authHttpResponseInterceptor', ['$q', function ($q) {
        return {
            request: function(config) {
                angular.element('#spinner').show();
                return config;
            },
            response : function(response) {
                angular.element('#spinner').fadeOut(3000);
                return response || $q.when(response);
            },
            responseError: function(reason) {
                angular.element('#spinner').fadeOut(3000);
                return $q.reject(reason);
            }
        };
    }]);



 .config(['$routeProvider', '$locationProvider', '$translateProvider', '$httpProvider',
            function ($routeProvider, $locationProvider, $translateProvider, $httpProvider) {
                $httpProvider.interceptors.push('authHttpResponseInterceptor');
    }
]);

in your Template
<div id="spinner"></div>


css   

#spinner,
#spinner:after {
  border-radius: 50%;
  width: 10em;
  height: 10em;
  background-color: #A9A9A9;
  z-index: 10000;
  position: absolute;
  left: 50%;
  bottom: 100px;
}
@-webkit-keyframes load8 {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
@keyframes load8 {
  0% {
    -webkit-transform: rotate(0deg);
    transform: rotate(0deg);
  }
  100% {
    -webkit-transform: rotate(360deg);
    transform: rotate(360deg);
  }
}
pengguna1853287
sumber
1
Jawaban hanya kode tidak banyak berguna.
Phantômaxx
0

buat direktif dengan kode ini:

$scope.$watch($http.pendingRequests, toggleLoader);

function toggleLoader(status){
  if(status.length){
    element.addClass('active');
  } else {
    element.removeClass('active');
  }
}
Oleg Ozimok
sumber
0

Solusi lain untuk menunjukkan pemuatan di antara berbagai perubahan url adalah:

$rootScope.$on('$locationChangeStart', function() {
  $scope.loading++;
});

$rootScope.$on('$locationChangeSuccess', function() {
  $timeout(function() {
    $scope.loading--;
  }, 300);
});

Dan kemudian di markup hanya beralih dengan pemintal ng-show="loading" .

Jika Anda ingin menampilkannya pada permintaan ajax tambahkan saja $scope.loading++ketika permintaan dimulai dan ketika itu berakhir tambahkan $scope.loading--.

Chrillewoodz
sumber
0

Anda dapat mencoba sesuatu seperti ini juga:

Buat arahan:

myApp.directive('loader', function () {
    return {
        restrict: 'A',
        scope: {cond: '=loader'},
        template: '<span ng-if="isLoading()" class="soft"><span class="fa fa-refresh fa-spin"></span></span>',
        link: function (scope) {
            scope.isLoading = function() {
                var ret = scope.cond === true || (
                        scope.cond &&
                        scope.cond.$$state &&
                        angular.isDefined(scope.cond.$$state.status) &&
                        scope.cond.$$state.status === 0
                    );
                return ret;
            }
        }
    };
}); 

Kemudian Anda menambahkan sesuatu seperti ini ke mainCtrl

    // Return TRUE if some request is LOADING, else return FALSE
    $scope.isLoading = function() {
        return $http.pendingRequests.length > 0;
    };

Dan HTML dapat terlihat seperti ini:

<div class="buttons loader">
    <span class="icon" loader="isLoading()"></span>
</div>
Andurit
sumber
0

Cara berikut akan mencatat semua permintaan, dan menyembunyikan hanya setelah semua permintaan dilakukan:

app.factory('httpRequestInterceptor', function(LoadingService, requestCount) {
    return {
        request: function(config) {
            if (!config.headers.disableLoading) {
                requestCount.increase();
                LoadingService.show();
            }
            return config;
        }
    };
}).factory('httpResponseInterceptor', function(LoadingService, $timeout, error, $q, requestCount) {
    function waitAndHide() {
        $timeout(function() {
            if (requestCount.get() === 0){
                LoadingService.hide();
            }
            else{
                waitAndHide();
            }
        }, 300);
    }

    return {
        response: function(config) {
            requestCount.descrease();
            if (requestCount.get() === 0) {
                waitAndHide();
            }
            return config;
        },
        responseError: function(config) {
            requestCount.descrease();
            if (requestCount.get() === 0) {
                waitAndHide();
            }
            var deferred = $q.defer();
            error.show(config.data, function() {
                deferred.reject(config);
            });
            return deferred.promise;
        }
    };
}).factory('requestCount', function() {
    var count = 0;
    return {
        increase: function() {
            count++;
        },
        descrease: function() {
            if (count === 0) return;
            count--;
        },
        get: function() {
            return count;
        }
    };
})

Yerken
sumber
0

Karena fungsionalitas posisi: diperbaiki berubah baru-baru ini, saya mengalami kesulitan menampilkan loader gif di atas semua elemen, jadi saya harus menggunakan jQuery inbuilt angular .

Html

<div ng-controller="FetchController">
      <div id="spinner"></div>
</div>

Css

#spinner {display: none}
body.spinnerOn #spinner { /* body tag not necessary actually */
   display: block;
   height: 100%;
   width: 100%;
   background: rgba(207, 13, 48, 0.72) url(img/loader.gif) center center no-repeat;
   position: fixed;
   top: 0;
   left: 0;
   z-index: 9999;
}
body.spinnerOn main.content { position: static;} /* and whatever content needs to be moved below your fixed loader div */

Pengendali

app.controller('FetchController', ['$scope', '$http', '$templateCache', '$location', '$q',
function($scope, $http, $templateCache, $location, $q) {

angular.element('body').addClass('spinnerOn'); // add Class to body to show spinner

$http.post( // or .get(
    // your data here
})
.then(function (response) {
    console.info('success');     
    angular.element('body').removeClass('spinnerOn'); // hide spinner

    return response.data;               
}, function (response) {                   
    console.info('error'); 
    angular.element('body').removeClass('spinnerOn'); // hide spinner
});

})

Semoga ini membantu :)

Magor Menessy
sumber
0

Semua jawaban atau rumit, atau perlu mengatur beberapa variabel pada setiap permintaan yang merupakan praktik yang sangat salah jika kita tahu konsep KERING. Contoh interseptor sederhana di sini, saya mengatur mouse menunggu ketika ajax mulai dan mengaturnya ke otomatis ketika ajax berakhir.

$httpProvider.interceptors.push(function($document) {
    return {
     'request': function(config) {
         // here ajax start
         // here we can for example add some class or show somethin
         $document.find("body").css("cursor","wait");

         return config;
      },

      'response': function(response) {
         // here ajax ends
         //here we should remove classes added on request start

         $document.find("body").css("cursor","auto");

         return response;
      }
    };
  });

Kode harus ditambahkan dalam konfigurasi aplikasi app.config. Saya menunjukkan cara mengubah mouse saat memuat tetapi di sana dimungkinkan untuk menampilkan / menyembunyikan konten loader, atau menambahkan, menghapus beberapa kelas css yang menunjukkan loader.

Interceptor akan berjalan pada setiap panggilan ajax, jadi tidak perlu membuat variabel boolean khusus ($ scope.loading = true / false dll.) Pada setiap panggilan http.

Maciej Sikora
sumber
0

Berikut ini adalah implementasi saya, sesederhana pertunjukan dan penghitung permintaan.

Itu menggunakan layanan baru untuk semua permintaan ke $ http:

myApp.service('RqstSrv', [ '$http', '$rootScope', function($http, $rootScope) {
    var rqstService = {};

    rqstService.call = function(conf) {

        $rootScope.currentCalls = !isNaN($rootScope.currentCalls) ?  $rootScope.currentCalls++ : 0;

        $http(conf).then(function APICallSucceed(response) {
            // Handle success
        }, function APICallError(response) {
            // Handle error
        }).then(function() {
            $rootScope.currentCalls--;
        });
    }
} ]);

Dan kemudian Anda dapat menggunakan basis loader Anda pada jumlah panggilan saat ini:

<img data-ng-show="currentCalls > 0" src="images/ajax-loader.gif"/>
Bancarel Valentin
sumber
0

jika Anda ingin menampilkan loader untuk setiap panggilan permintaan http maka Anda dapat menggunakan pencegat sudut untuk mengelola panggilan permintaan http,

di sini adalah kode sampel

<body data-ng-app="myApp">
<div class="loader">
    <div id="loader"></div>
</div>

<script>
    var app = angular.module("myApp", []);

    app.factory('httpRequestInterceptor', ['$rootScope', '$location', function ($rootScope, $location) {
        return {
            request: function ($config) {
                $('.loader').show();
                return $config;
            },
            response: function ($config) {
                $('.loader').hide();
                return $config;
            },
            responseError: function (response) {
                return response;
            }
        };
    }]);

    app.config(['$stateProvider', '$urlRouterProvider', '$httpProvider',
        function ($stateProvider, $urlRouterProvider, $httpProvider) {
            $httpProvider.interceptors.push('httpRequestInterceptor');
        }]);

</script>
</body>
Om Sharma
sumber
0

Cukup gunakan ng-show dan boolean

Tidak perlu menggunakan arahan, tidak perlu rumit.

Berikut adalah kode yang akan diletakkan di sebelah tombol kirim atau di mana pun Anda menginginkan pemintal:

<span ng-show="dataIsLoading">
  <img src="http://www.nasa.gov/multimedia/videogallery/ajax-loader.gif" style="height:20px;"/>
</span>

Dan kemudian di controller Anda:

$scope.dataIsLoading = true

let url = '/whatever_Your_URL_Is'
$http.get(url)
.then(function(response) {
  $scope.dataIsLoading = false
})
Adam
sumber
-1

Berikut adalah solusi saya yang saya rasa banyak easer yang diposting di sini. Tidak yakin seberapa "cantik" itu, tapi itu menyelesaikan semua masalah saya

Saya memiliki gaya css yang disebut "memuat"

.loading { display: none; }

Html untuk memuat div bisa apa saja tetapi saya menggunakan beberapa ikon FontAwesome dan metode putaran di sana:

<div style="text-align:center" ng-class="{ 'loading': !loading }">
    <br />
    <h1><i class="fa fa-refresh fa-spin"></i> Loading data</h1>
</div>

Pada elemen yang ingin Anda sembunyikan, cukup tulis ini:

<something ng-class="{ 'loading': loading }" class="loading"></something>

dan dalam fungsi saya hanya mengatur ini pada beban.

(function (angular) {
    function MainController($scope) {
        $scope.loading = true

Saya menggunakan SignalR sehingga dalam fungsi hubProxy.client.allLocks (ketika selesai melalui kunci) saya menjorok menempatkan

 $scope.loading = false
 $scope.$apply();

Ini juga menyembunyikan {{someField}} ketika halaman memuat karena saya mengatur kelas memuat pada beban dan AngularJS menghapusnya setelah itu.

stibay
sumber