AngularJS에서 $ http 요청 중에 spinner GIF를 표시 하시겠습니까?


234

내가 사용하고 $httpAjax 요청을 만들기 위해 AngularJS와의 서비스.

Ajax 요청이 실행되는 동안 스피너 GIF (또는 다른 유형의 통화 중 표시기)를 어떻게 표시 할 수 있습니까?

ajaxstarteventAngularJS 문서에서 와 같은 것을 보지 못했습니다 .


2
HTTP 인터셉터를 기반으로 간단한 스피너를 원한다면 각도 모듈이 있습니다. 유명한 Ihamified Sham 스피너를 사용합니다. 살펴보기 : github.com/harinair/angular-sham-spinner
Hari Gangadharan

1
나는의 플러그인 썼다 각도-httpshooter , 그냥 전화 촬영하기 전에 구성 데이터와 이벤트를 해제하고 단지 resposne을 잡 후 다른 해제, 당신은 이러한 이벤트를 잡는 글로벌 로더를 쓸 수 있습니다
싯다 르트 나라 얀

답변:


88

현재 과거 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']).
//.......

나머지는 다음과 같습니다 (HTML / CSS) .... 사용

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

토글합니다. 참고 : 위는 포스트 시작시 각도 모듈에서 사용됩니다

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

19
참고 사용할 수있는 angular.element('#mydiv').show()대신에$('#mydiv').show()
JMaylin

8
페이지가 여러 ajax 요청을하는 경우에는 작동하지 않습니다. 첫 번째 요청이 끝나면 로딩 gif가 숨겨집니다.
Meeker

38
승인 된 솔루션이 위반하는 AngularJS의 모범 사례에 따르면 지시문 외부에서 DOM을 수정해서는 안됩니다. 지시문 내에서 요소에 대한 표시 / 숨기기를 호출하십시오.
Mariusz

7
나는 충분히 의견을 알지 잘 모르겠습니다 ... 그러나 이것을 수행하는 올바른 방법 ng-class은 JQuery를 사용하여 요소를 표시하고 숨기는 대신 지시문을 사용하는 것입니까?
James Heald

2
@JamesHeald는 정확합니다. Angular의 모든 DOM 조작에 jQuery를 사용할 필요가 없습니다. ng-class, ng-if, ng-hide, ng-show 등을 살펴보십시오. 필요한 거의 모든 것에 대한 지시문이 있습니다.
jKlaus

471

이것은 실제로 특정 사용 사례에 따라 다르지만 간단한 방법은 다음과 같은 패턴을 따릅니다.

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

그런 다음 템플릿에서 반응하십시오.

<div class="spinner" ng-show="loading"></div>
<div ng-repeat="item in items>{{item.name}}</div>

223
동시에 여러 개의 ajax 요청이있는 경우 요청이 시작될 때와 종료 할 때 loading정수로 선언 할 수 있습니다 . 템플릿에서 변경할 사항이 없습니다. 이 진행 중 적어도 하나 개의 요청이며, 나머지 시간 숨겨져 때 스피너가 표시됩니다 그래서$scope.loading = 0;$scope.loading++;$scope.loading--;
JMaylin

16
오류 폴백 기능에서도 loading을 false로 설정해야합니다.
sebnukem

3
@sebnukem 맞습니다. 이것은 꽤 높은 수준의 예 였지만 명확성을 위해 어쨌든 추가했습니다. 피드백 감사드립니다!
Josh David Miller

1
@JMaylin-$ scope.loading에서 $ watch를 사용할 수 있습니다. 다른 작업을 수행하십시오
Jason

5
$scope.loading = false성공과 실패 콜백을 모두 넣는 대신보다 확실한 방법 은에 콜백하는 것 .finally()입니다. : 그것은처럼 보일 것mySvc.get().then(success, fail).finally(function() { $scope.loading = false; });

44

여기에 사용 된 버전입니다 directiveng-hide.

앵귤러 서비스 를 통한 모든 호출 중에 로더가 표시됩니다 $http.

템플릿에서 :

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

지령:

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

ng-hide요소 에서 클래스를 사용하면 jquery를 피할 수 있습니다.


맞춤 설정 : interceptor

로딩 인터셉터를 작성하면 조건에 따라 로더를 표시하거나 숨길 수 있습니다.

지령:

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

인터셉터 :

  • 예를 들면 : 표시되지 않는 spinner경우response.background === true;
  • 가로 채기 request및 / 또는 response설정 $rootScope.$broadcast("loader_show");또는$rootScope.$broadcast("loader_hide");

인터셉터 작성에 대한 추가 정보


@punkrockpolly 내 특정 시나리오에는 서비스를 호출하는 두 개의 개별 구성 요소가 있습니다. 그러나 이것은 그중 하나에 대해서만 작동합니다.이 재사용 가능하도록 매개 변수 또는 무언가를 전달해야합니까?
RicardoGonzales

@razorblade $http는 모든 서비스에서 전화를 걸 때마다 회전 합니다.
punkrockpolly

31

ngResource를 사용하는 경우 객체의 $ resolved 속성이 로더에 유용합니다.

다음과 같은 자원의 경우 :

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

로더를 자원 오브젝트의 $ resolved 속성에 링크 할 수 있습니다.

<div ng-hide="user.$resolved">Loading ...</div>


13

angular-busy비동기 호출에 따라 작은 로더를 표시하는 지시문을 발견했습니다 .

예를 들어을 (를) 만들어야하는 GET경우 $scope,

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

다음과 같이 호출하십시오.

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

여기 GitHub있습니다.

다음을 사용하여 설치할 수도 bower있습니다 (프로젝트 종속성을 업데이트하는 것을 잊지 마십시오).

bower install angular-busy --save

설명서에서 "일부 요소를 비활성화"하는 방법을 찾을 수 없습니다. 어떻게 설명 할 수 있습니까? 예를 들어, 스피너가 표시된 상태에서 버튼을 비활성화하고 싶습니다.
c4k

앵귤러 바쁜는 요소에 마스크 만 넣었으므로 원하는대로 단추를 비활성화 할 수는 없지만 빈 템플릿으로 배경을 설정 하여이 인상을 줄 수 있습니다. 저는 원어민이 아닙니다. 혼란을 드려 죄송합니다.
Balthazar

좋아, 나는 다른 사람이 같은 혼란을 갖지 않도록 답변을 편집했습니다. 다른 프랑스어로 영어를 사용하는 프랑스어는 항상 혼란스러워 :)
c4k

5

api 호출을 서비스 / 공장 내에서 래핑하는 경우 응답 카운터 및 @JMaylin의 탁월한 동시 제안에 따라로드 카운터를 추적하고 지시문을 통해로드 카운터를 참조 할 수 있습니다. 또는 이들의 임의의 조합.

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

스피너 지시

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

용법

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

5

페이지로드 및 모달의 경우 가장 쉬운 방법은 ng-show지시문을 사용하고 범위 데이터 변수 중 하나를 사용하는 것입니다. 다음과 같은 것 :

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

여기에 someObject정의되지 않은 동안 스피너가 표시됩니다. 서비스가 데이터와 함께 반환되고 someObject채워지면 스피너는 숨겨진 상태로 돌아갑니다.


3

이것은 내가 생각하는 스피너를 추가하는 가장 쉬운 방법입니다.

이 아름다운 스피너 중 하나의 div 태그와 함께 ng-show를 사용할 수 있습니다. http://tobiasahlin.com/spinkit/ {{This is not my page}}

그런 다음 이런 종류의 논리를 사용할 수 있습니다

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


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>

이 CSS를 추가하십시오.

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

그리고 각도에서 추가하십시오.

$ rootScope.loading = 거짓; $ rootScope.loading = true; -> $ http.get이 종료 될 때


2

@bulltorious의 위대한 답변에 대한 내 버전을 공유하고 최신 각도 빌드 (이 코드와 함께 버전 1.5.8을 사용함)로 업데이트했으며 여러 동시 요청에 견딜 수 있도록 카운터를 사용하는 @JMaylin의 아이디어를 통합했습니다. 최소 밀리 초 미만의 요청에 대한 애니메이션 표시를 건너 뛰는 옵션 :

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

2

각도 인터셉터를 사용하여 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


2

인터셉터 또는 jQuery가없는 간단한 방법

타사 라이브러리, 인터셉터 또는 jQuery가 필요없는 스피너를 표시하는 간단한 방법입니다.

컨트롤러에서 플래그를 설정하고 재설정하십시오.

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

HTML에서 플래그를 사용하십시오.

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

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

vm.starting플래그가 설정되어 trueXHR이 시작되고이 때 XHR의 완료를 클리어 할 때.


1

이것은 나를 위해 잘 작동합니다 :

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>

모난:

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

$ http에서 반환 된 약속은 보류 중이지만 ng-show는이를 "거만한"것으로 평가합니다. 이것은 약속이 해결되면 자동으로 업데이트됩니다 ... 정확히 우리가 원하는 것입니다.


이것은 역동적 인 방법이 아닙니다.
Umair Hamid 2016 년

이것이 왜이 목표를 달성하기위한 역동적 인 방법이 아니라고 생각하는지 설명해 주시겠습니까? 이것은이 게시물을 읽는 다른 사람들이 배우는 데 도움이 될 것입니다. 감사합니다.
dank

신청서에 여러 개의 요청이 있습니다. $ scope.req는 단일 요청에 대해서만 작동합니다. 이 특정 요청 완료 로더가 숨겨지고 다른 요청을 완료하기를 기다리지 않습니다. 이를 달성하는 가장 좋은 방법은 인터셉터를 사용하는 것입니다.
Umair Hamid 2016 년

1

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

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

1
코드 전용 답변은별로 유용하지 않습니다.
Phantômaxx

0

이 코드로 지시문을 작성하십시오.

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

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

0

다른 URL 변경 사이에로드를 표시하는 또 다른 솔루션은 다음과 같습니다.

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

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

그런 다음 마크 업에서 스피너를로 전환하십시오 ng-show="loading".

아약스 요청에 그것을 표시 $scope.loading++하려면 요청이 시작될 때와 끝날 때 add 추가하십시오 $scope.loading--.


0

다음과 같이 시도해 볼 수도 있습니다.

지시문 작성 :

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

그런 다음 mainCtrl에 이와 같은 것을 추가하십시오.

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

HTML은 다음과 같습니다.

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

0

다음 방법은 모든 요청을 기록하고 모든 요청이 완료된 후에 만 ​​숨 깁니다.

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


0

position : fixed 의 기능이 최근에 변경되었으므로 모든 요소 위에 gif 로더를 표시하는 데 어려움이 있었으므로 angular의 내장 jQuery 를 사용해야했습니다 .

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

제어 장치

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

})

도움이 되었기를 바랍니다 :)


0

모든 답변은 복잡하거나 복잡하거나 모든 요청에 ​​대해 일부 변수를 설정해야합니다 .DRY 개념을 알고 있다면 매우 잘못된 연습입니다. 여기 간단한 인터셉터 예제, ajax가 시작될 때 마우스를 대기 상태로 설정하고 ajax가 끝나면 자동으로 설정했습니다.

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

응용 프로그램 구성에서 코드를 추가해야합니다 app.config. 로딩 상태에서 마우스를 변경하는 방법을 보여 주었지만 로더 내용을 표시하거나 숨기거나 로더를 표시하는 CSS 클래스를 추가, 제거 할 수 있습니다.

인터셉터는 모든 ajax 호출에서 실행되므로 모든 http 호출에서 특수 부울 변수 ($ scope.loading = true / false 등) 를 작성할 필요가 없습니다 .


0

다음은 ng-show 및 요청 카운터처럼 간단한 구현입니다.

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

그런 다음 현재 통화 수에 따라 로더 기반을 사용할 수 있습니다.

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

0

모든 http 요청 호출에 대해 로더를 표시하려면 각도 인터셉터를 사용하여 http 요청 호출을 관리 할 수 ​​있습니다.

다음은 샘플 코드입니다

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

0

ng-show와 boolean을 사용하십시오.

지시문을 사용할 필요가없고 복잡 할 필요가 없습니다.

제출 버튼 옆에 또는 회전자가 원하는 위치에 넣는 코드는 다음과 같습니다.

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

그런 다음 컨트롤러에서 :

$scope.dataIsLoading = true

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

-1

여기에 내가 생각하는 내 솔루션은 다른 사람이 여기에 게시 한 것이 훨씬 쉽습니다. 그것이 얼마나 "예쁜"지 모르겠지만 모든 문제를 해결했습니다.

"로드 중"이라는 CSS 스타일이 있습니다

.loading { display: none; }

로딩 div의 html은 무엇이든 될 수 있지만 FontAwesome 아이콘과 spin 방법을 사용했습니다.

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

숨기려는 요소에 간단히 다음과 같이 작성하십시오.

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

그리고 기능에서 나는 이것을로드시 설정했습니다.

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

hubProxy.client.allLocks 함수에서 SignalR을 사용하고 있습니다 (잠금을 완료했을 때).

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

또한 로딩 클래스를로드 할 때 페이지를로드 할 때 {{someField}}을 숨기고 AngularJS는 나중에 페이지를 제거합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.