1
votes
<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); 
};
1
What is your question? - Gabriel Hautclocq
Why are u using $q in your service? - Vivz
Vivz is right, you should return boolean values in IsValidImageUrl function. - Gaurav Srivastava
@GauravSrivastava how do I return boolean. I think image.onerror or image.onload is async - kittu

1 Answers

1
votes

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.