kittu
kittu

Reputation: 7008

Error while testing image source on load in angular

<div class="col-xs-4 col-sm-4 col-md-4">
    {{jsonData[current].profilepic}}
    <div ng-if=IsValidImageUrl(jsonData[current].profilepic)>
        <img id="pic" ng-src="{{jsonData[current].profilepic}}"  alt=""/>
    </div>
    <div ng-if=!IsValidImageUrl(jsonData[current].profilepic)>
        <div id="pic" class="letter">
            <div class="circle">{{jsonData[current].firstName.charAt(1)+jsonData[current].lastName.charAt(1)}}</div>
        </div>
    </div>
</div>

controller:

app.controller('task1Controller',['$scope', 'taskFactory', '$state', 'imageTestService', function($scope, taskFactory, $state, imageTestService){

    $scope.taskData = {};
    $scope.current = 0;

    taskFactory.get().then(function(response){
        $scope.jsonData = response.data.data.resultCareGivers;
    });

    $scope.IsValidImageUrl = function(url){        
        return imageTestService.IsValidImageUrl(url); //Error here
    };

    $scope.viewDetails = function(){
        $state.go('view-details', {details: $scope.jsonData[$scope.current]});
    };


    $scope.back = function(){
        $scope.current = ($scope.current !== 0 ? $scope.current - 1 : 0);
    };

    $scope.next = function(){
        $scope.current = ($scope.current !== $scope.jsonData.length-1 ? $scope.current + 1 : $scope.jsonData.length-1);
    };

}]);

image test service:

app.service('imageTestService', function($q){

    this.IsValidImageUrl = function(url){
        var deferred = $q.defer();
        if(url != null && url != ""){
            var img = new Image();
            img.onerror = function() { deferred.resolve(false); };
            img.onload =  function() { deferred.resolve(true); };
            img.src = url;
            return deferred.promise;
        }
    };

});

Error stack in console:

Error link

10 $digest() iterations reached. Aborting! Watchers fired in the last 5 iterations: [[{"msg":"IsValidImageUrl(jsonData[current].profilepic)","newVal":{"$$state":{"status":0}},"oldVal":{"$$state":{"status":0}}}],[{"msg":"IsValidImageUrl(jsonData[current].profilepic)","newVal":{"$$state":{"status":0}},"oldVal":{"$$state":{"status":0}}}],[{"msg":"IsValidImageUrl(jsonData[current].profilepic)","newVal":{"$$state":{"status":0}},"oldVal":{"$$state":{"status":0}}}],[{"msg":"IsValidImageUrl(jsonData[current].profilepic)","newVal":{"$$state":{"status":0}},"oldVal":{"$$state":{"status":0}}}],[{"msg":"IsValidImageUrl(jsonData[current].profilepic)","newVal":{"$$state":{"status":0}},"oldVal":{"$$state":{"status":0}}}]]

Update 2:

app.service('imageTestService', function(){

    this.IsValidImageUrl = function(url){
        var result = {};
        if(url != null && url != ""){
            var img = new Image();
            img.onerror = function() { result.val = true };
            img.onload =  function() { result.val = false };
            return result;
        }
    };
});

but still the same error in console.

Update 3:

app.service('imageTestService', function(){

    this.IsValidImageUrl = function(url){
        var result = {
            val :false
        };
        this.img = new Image();
        this.img.onabort = function() { result.val = false };
        this.img.onerror = function() { result.val = false };
        this.img.onload =  function() { result.val = true };
        return result.val;
    };
});

In update 3, doesn't matter what I do, always image.onabort() is called.

It throws error fails to load resource at the function call itself:

$scope.IsValidImageUrl = function(url){    //Failed to load resource error    
   return imageTestService.IsValidImageUrl(url); 
};

Upvotes: 1

Views: 897

Answers (1)

Maxim Shoustin
Maxim Shoustin

Reputation: 77904

Short Answer

To get rid of this error we need case where IsValidImageUrl() method should return explicit result.

For example you can initialize result with default value false:

 this.IsValidImageUrl = function(url){
    var result = {
      val:false
    };
    if(url != null && url != ""){
        var img = new Image();
        img.onerror = function() { result.val = true };
        img.onload =  function() { result.val = false };
        return result.val;
    }
};

Demo with 10 $digest() iterations reached error

fixed Demo


Long Answer

First off lets understand why we get 10 $digest() iterations reached. Aborting!. Generally its a guard of Angular to get rid of infinite loop of digest cycles that will cause to memory leak and at the end page stuck.

In our case once IsValidImageUrl will return different result, Angular will fire new digest cycle and so on - that will lead to above mentioned error.


Its not good practice to call methods from ng-if | ng-show/hide | ng-style .... - its a over kill and will effect on your page performance.

I suggest you to call IsValidImageUrl(jsonData[current].profilepic) from controller and store it somewhere. for ng-if we need boolean value only.

FYI, Image.onload and Image.onError are callbacks therefore 1st you return empty object result and after some delay you update result content with Image.onload or Image.onError callbacks that will fire new digest cycle that will lead to additional call of IsValidImageUrl()`.

ngIf directive is a watcher that listens on result and after 10 loops will throw 10 $digest() iterations reached. Aborting! exception.


Upvotes: 1

Related Questions