noobavistic
noobavistic

Reputation: 43

ng-repeat not processing upon FileReader

So this is how my view looks:

<body ng-controller="AdminCtrl">
<img ng-repeat="pic in pics" ng-src="{{pic}}" />
<form ng-submit="postPic()">
    <input id="photos" type="file" accept="image/*" multiple/>
    <button>Add Pics</button>
</form>

And this is the controller:

app.controller('AdminCtrl',['$scope', function($scope){
    $scope.pics =[];

    $scope.postPic = function() {
        var files = $('#photos').get(0).files;

        for (var i = 0, numFiles = files.length; i < numFiles; i++) {
            var photoFile = files[i];
            var reader = new FileReader();
            reader.onloadend = function(e){
                $scope.pics.push(e.target.result);
                console.log($scope.pics);
            };
            reader.readAsDataURL(photoFile);
        }
    };

Although I choose many files and they show up in the console as well (although asynchronously), I can't seem to update the view based on the update of $scope.pics. Isn't $scope.pics being watched? Why is this happening?

Upvotes: 3

Views: 172

Answers (1)

tommybananas
tommybananas

Reputation: 5736

The problem is that you are altering the $scope object asynchronously so angular is not aware of the changes that it needs to process. Angular does not constantly "watch" your $scope object. The reason you typically don't have to explicitly use $scope.$apply() is because angular will automatically do this for you most of the time if you are inside the angular ecosystem (ie: controller constructors, $scope functions, etc).

app.controller('AdminCtrl',['$scope', function($scope){
    $scope.pics =[];

    $scope.postPic = function() {
        var files = $('#photos').get(0).files;

    for (var i = 0, numFiles = files.length; i < numFiles; i++) {
        var photoFile = files[i];
        var reader = new FileReader();
        reader.onloadend = function(e){
            $scope.pics.push(e.target.result);
            console.log($scope.pics);
            $scope.$apply(); // force digest cycle
         };
         reader.readAsDataURL(photoFile);
    }
};

This is the same reason angular provides the $timeout service, which is only a wrapper for setTimeout but will trigger a digest cycle for you automatically: https://stackoverflow.com/a/19609851/580487

TLDR; Async functionality [aside from built in angular stuff] is outside of the angular ecosystem so you must let angular know about $scope changes via $scope.$apply()

Upvotes: 4

Related Questions