I'm creating a simple image uploading page that works with AWS S3 using Danial Farid's ng-file-upload plugin. It features a simple button to upload a new image and a list of images. Like this:
<ul>
<li ng-repeat="image in product.images">
<a class="thumbnail" href="{{ image }}" target="_blank">
<img ng-src="{{ image }}" alt="image">
</a>
</li>
<li>
<div class="btn-image-upload"
ngf-select
ngf-change="upload($files)"
ngf-accept="'image/*'"></div>
</li>
</ul>
On my controller:
$scope.upload = function (files) {
var aws_policy, aws_policy_signature;
if (files && files.length) {
$http
.get(API_URL+'/helper/aws_policy')
.then(function(data) {
aws_policy = data.data.policy;
aws_policy_signature = data.data.signature;
for (var i = 0; i < files.length; i++) {
var file = files[i];
var key = generate_aws_key() + '.' + file.name.split('.').pop();
var base_url = 'https://.../';
Upload
.upload({ ... })
.success(function( data, status, headers, config ) {
console.log($scope.product);
$scope.product.images.push( base_url + key );
console.log($scope.product);
});
}
});
}
};
The file is being uploaded properly (I get a nice 204 Success
from AWS) and the two console.log($scope.product)
's get called showing the appropriate results (the second one features the item on the images
array).
Here's the thing. This baby works perfectly on my development machine, but sometimes on the staging or production servers, the list of images is not being updated when $scope.product.images
is. By sometimes, I mean that it does it 1/3rd of the times.
Summarizing
Sometimes, only on my production server, the DOM is not updated when $scope.product.images
is updated inside AngularJS digest.
My programming experience taught me that sometimes is not an acceptable concept in this type of matters and that it must be related to something that always happens when this problem arises, but I debugged extensively and failed to find the real cause. Ideas?
It's very likely caused by looping within asynchronous callbacks:
You have to freeze the value of i
:
$scope.upload = function (files) {
var aws_policy, aws_policy_signature;
function upload(index) {
var file = files[index];
var key = generate_aws_key() + '.' + file.name.split('.').pop();
var base_url = 'https://.../';
Upload
.upload({ ... })
.success(function( data, status, headers, config ) {
console.log($scope.product);
$scope.product.images.push( base_url + key );
console.log($scope.product);
});
}
if (files && files.length) {
$http
.get(API_URL+'/helper/aws_policy')
.then(function(data) {
aws_policy = data.data.policy;
aws_policy_signature = data.data.signature;
for (var i = 0; i < files.length; i++) {
var file = files[i];
upload(i);
}
});
}
};