In most of the fiddles containing sample usage code for ng-file-upload (https://github.com/danialfarid/ng-file-upload) like the one at (http://jsfiddle.net/danialfarid/maqbzv15/1118/), the upload response callback functions wrap their code in a $timeout
service call, but these calls do not have any delay parameter passed in.
The Angular.js docs for $timeout
(https://docs.angularjs.org/api/ng/service/$timeout) indicate that the delay is optional, but why would you want to make a call to $timeout
if not to delay the code being run. In other words instead of the following, why not do the one after:
//inject angular file upload directives and services.
var app = angular.module('fileUpload', ['ngFileUpload']);
app.controller('MyCtrl', ['$scope', 'Upload', '$timeout', function ($scope, Upload, $timeout) {
$scope.uploadPic = function(file) {
file.upload = Upload.upload({
url: 'https://angular-file-upload-cors-srv.appspot.com/upload',
data: {username: $scope.username, file: file},
});
file.upload.then(function (response) {
$timeout(function () {
file.result = response.data;
});
}, function (response) {
if (response.status > 0)
$scope.errorMsg = response.status + ': ' + response.data;
}, function (evt) {
// Math.min is to fix IE which reports 200% sometimes
file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
});
}
}]);
Is there any reason for the $timeout
wrapper in all these examples? Would the following file.upload call work in its place?:
file.upload.then(function (response) {
file.result = response.data;
}, function (response) {
if (response.status > 0)
$scope.errorMsg = response.status + ': ' + response.data;
}, function (evt) {
// Math.min is to fix IE which reports 200% sometimes
file.progress = Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
});
Edit: I can see that it appears to run without the $timeout
wrapper, but the fact it's included in all the examples makes me think it's deliberate, which probably means there's a security/robustness/browser compatibility edge case I don't understand here.
It's all to do with Angular's digest cycle. I'll try to demonstrate this with an example before I go on to explain what the digest cycle is. Imagine the following code:
There's an inherent problem with this code. As much as we change the variable of
$scope.name
after 2 seconds, Angular is completely unaware of this change to$scope.name
. If you now consider the following example where we use$timeout
instead:Angular will call the anonymous function after two seconds, however, it will then start off Angular's digest cycle. This is the main difference between
$timeout
andsetTimeout
, the digest cycle being run.The digest cycle is (put simply) Angular going over all of the watchers (bindings), checking for any changes and re-rendering where appropiate. You may have seen a mention to
$scope.$apply
elsewhere - this is how to start the digest cycle.With regards to the example you provided: If the
$timeout
wasn't used, Angular wouldn't be aware that any changes have been made and as such, your view wouldn't update. I mentioned$scope.$apply
earlier so you may be wondering why we don't just use this instead? The problem with using$scope.$apply
is that you cannot be sure that a digest cycle isn't in progress already. If you do call it while one is occcuring, you'll see an error "$digest is already in progress
".$timeout
will only run after the current cycle and as such, this error won't happen.People often use
$timeout
without any delay to notify Angular that a change has been made by a third party (like your file uploader), that it otherwise wouldn't know had happened.Hopefully this clears things up.
Tom
$timeout
can be used to invoke any callback asynchronously. e.g.This means that all javascript will finish running before your callback is invoked. Adding a
delay
parameter to thetimeout
will delay the callback invocation approximately that much further, but you still gain asynchronous behavior whether or not adelay
is provided.