Установите переменную rootScope в httpIntercept
Я хотел бы иметь возможность установить http-перехватчик AngularJS, который будет устанавливать $rootScope.loading
в true
или же false
в зависимости от того, выполняется ли в данный момент запрос AJAX.
Пока я собрал следующее:
angular.module('myApp')
.config(function ($httpProvider) {
$httpProvider.responseInterceptors.push('loadingInterceptor');
var loadingFunction = function (data, headersGetter) {
$rootScope.loading = true
return data;
};
$httpProvider.defaults.transformRequest.push(loadingFunction);
})
.factory('loadingInterceptor', function ($q, $window, $rootScope) {
return function (promise) {
return promise.then(function (response) {
$rootScope.loading = false;
return response;
}, function (response) {
$rootScope.loading = false;
return $q.reject(response);
});
};
});
Но я не могу вводить $rootScope
в блок конфигурации, поэтому у меня нет возможности установить $rootScope.loading
переменная, когда начинается HTTP-запрос.
Я что-то здесь упускаю? Как мне это сделать?
3 ответа
responseInterceptors
устарел http://docs.angularjs.org/api/ng.%24htt. Я улучшил предыдущий пример:
app.factory('myHttpInterceptor', ['$q', '$rootScope', '$injector',
function ($q, $rootScope, $injector) {
$rootScope.showSpinner = false;
$rootScope.http = null;
return {
'request': function (config) {
$rootScope.showSpinner = true;
return config || $q.when(config);
},
'requestError': function (rejection) {
$rootScope.http = $rootScope.http || $injector.get('$http');
if ($rootScope.http.pendingRequests.length < 1) {
$rootScope.showSpinner = false;
}
if (canRecover(rejection)) {
return responseOrNewPromise
}
return $q.reject(rejection);
},
'response': function (response) {
$rootScope.http = $rootScope.http || $injector.get('$http');
if ($rootScope.http.pendingRequests.length < 1) {
$rootScope.showSpinner = false;
}
return response || $q.when(response);
},
'responseError': function (rejection) {
$rootScope.http = $rootScope.http || $injector.get('$http');
if ($rootScope.http.pendingRequests.length < 1) {
$rootScope.showSpinner = false;
}
if (canRecover(rejection)) {
return responseOrNewPromise
}
return $q.reject(rejection);
}
}
}
]);
И вы можете использовать фабрику так:
app.config(function ($httpProvider) {
$httpProvider.interceptors.push('myHttpInterceptor');
});
Вы можете вставлять только провайдеры в module.config, но вы все равно не должны делать это в преобразователях по умолчанию, вы должны делать это в перехватчиках (как вы делаете, когда устанавливаете load = false).
Может быть несколько запросов одновременно. Нечто подобное может работать:
angular.module('myApp')
.config(function ($httpProvider) {
$httpProvider.responseInterceptors.push(function ($rootScope) {
$rootScope.numLoadings = 0;
$rootScope.loading = false;
return function (promise) {
$rootScope.numLoadings++;
$rootScope.loading = true;
// make sure the loading screen is visible
var hide = function (r) {
if ((--$rootScope.numLoadings)===0){
//console.log('hide the loading screen');
$rootScope.loading = false;
}
return r;
};
return promise.then(hide, hide);
};
});
});
Конечно, вам не нужно помещать numLoadings в корневую область, я просто поместил его для этого примера: http://plnkr.co/edit/32Mh9UOS3Z4vnOtrH9aR?p=preview
module.config
имеет дело только с поставщиками, и вы не должны пытаться получить доступ к $ rootScope отсюда.
Кроме того, я не вижу причин для подсчета количества ожидающих запросов вручную, поскольку $http
обслуживание и, ну... нет необходимости делать одну и ту же работу дважды:)
CoffeeScript
angular.module('app.services.networkStatusIndicator', []).config([
'$httpProvider'
( $httpProvider )->
# Network status indicator
# ========================
# Monitor XHTTP requests globally and update UI accordigly.
$http = null
interceptor = ['$q', '$injector', '$rootScope' , ($q, $injector, $rootScope )->
success = (response)->
$http = $http or $injector.get '$http'
if $http.pendingRequests.length < 1
$rootScope.networkStatus = 'idle'
response
error = (response)->
$http = $http or $injector.get '$http'
if $http.pendingRequests.length < 1
$rootScope.networkStatus = 'idle'
$q.reject response
(promise)->
$rootScope.networkStatus = 'loading'
promise.then success, error
]
$httpProvider.responseInterceptors.push interceptor
])
Javascript
angular.module('app.services.networkStatusIndicator', []).config([
'$httpProvider', function($httpProvider) {
var $http, interceptor;
$http = null;
interceptor = [
'$q', '$injector', '$rootScope', function($q, $injector, $rootScope) {
var error, success;
success = function(response) {
$http = $http || $injector.get('$http');
if ($http.pendingRequests.length < 1) {
$rootScope.networkStatus = 'idle';
}
return response;
};
error = function(response) {
$http = $http || $injector.get('$http');
if ($http.pendingRequests.length < 1) {
$rootScope.networkStatus = 'idle';
}
return $q.reject(response);
};
return function(promise) {
$rootScope.networkStatus = 'loading';
return promise.then(success, error);
};
}
];
return $httpProvider.responseInterceptors.push(interceptor);
}
]);