I am trying to add a 'loading' class to an element until an asynchronous call is finished. To do so, I am using a variable named loading that I use like so:
<div class='ui segment' ng-class="{'loading': loading == true}">
To trigger the call, I am using another element with ng-click :
<i class='...' ng-click="action('deleteGlobal', false)"></i>
This will call the method deleteGlobal of the variable project in my controller's $scope, and provide a callback :
$scope.action = (action, redirect) => {
delete $scope.error;
$scope.loading = true;
$timeout(() => {
$scope.project[action]((err) => {
$scope.loading = false;
if (err)
$scope.error = err;
else if (redirect)
$state.go('projects.all');
});
})
}
project is an instance of my custom class ProjectManager. This is its method deleteGlobal :
deleteGlobal (callback) {
window.setTimeout(() => {
callback();
}, 1000)
}
(Here, the setTimeout is only used to simulate a long operation since that is what I plan to replace this code with later on)
So with this code, I expect $scope.loading to become false once the callback is called. And with a couple of console.logs I saw that was indeed the case. However, the 'loading' class of my element is not removed accordingly.
I read about $scope.$apply() and tried to wrap my async call in it but it didn't work. In fact, it even triggered an error: '$apply already in progress'.
Thanks in advance!
In general with AngularJS, third-party callback-based APIs are integrated with the framework by converting them to $q promises:
function apiPromise(callbackBasedApi) {
var defer = $q.defer()
callbackBasedApi( (value,err) => {
̶c̶a̶l̶l̶b̶a̶c̶k̶(̶)̶;̶
if (value) {
defer.resolve(value);
} else {
defer.reject(err)
};
})
return defer.promise;
}
Then use the .then
method of the returned promise:
$scope.action = (action, redirect) => {
delete $scope.error;
$scope.loading = true;
var promise = apiPromise($scope.project[action])
.then(function(value) {
if (redirect)
$state.go('projects.all');
};
})
.catch(function(err) {
$scope.error = err;
})
.finally(function() {
$scope.loading = false;
});
}
Promises created with the $q
service are integrated with the AngularJS framework and its digest cycle. Operations which are applied in the AngularJS execution context will automatically benefit from AngularJS data-binding, exception handling, property watching, etc.