3

I'd like to check an image to see if the resource is available, before displaying it. I found a good way to do that in AngularJS here: Angular js - isImage( ) - check if it's image by url

But every time I try to implement it, an infinite loop is triggered, even if I reduce the function to its simplest form in a codepen : https://codepen.io/anon/pen/mBwgbE

test image function (js)

$scope.testImage = function(src) {
    console.log('function triggered');
                Utils.isImage(src).then(function(result) {
             return "result";
         });
    };

Usage (html)

<h3>Image link broken<h3>
<p>{{testImage('anylink')}}</p>

<h3>Image link OK<h3>
<p>{{testImage('http://lorempixel.com/400/200/sports/1/')}}</p>

Can anyone explain this behaviour to me, and help me fix it?

2 Answers 2

3

Angular runs the digest loop, and interprets your template. It sees {{testImage('anylink')}} and calls into it. This calls into Utils.isImage, which creates a promise. The promise is returned to testImage, but testImage itself doens't return anything, so the template shows nothing.

A little later, the promise resolves. Angular sees this, so it runs the digest loop and interprets your template. It sees {{testImage('anylink')}} and calls into it. This calls into Utils.isImages, which creates a prom... oh crap, we're in an loop. It's going to call isImage, which creates a promise, and then when that promise resolves, it interprets the template again and calls isImage, starting all over.

Instead, i would recommend that when your controller loads, you create the promises right then, and when they resolve, you stick whatever values you need from them onto the controller as concrete values. Something like this:

function myController($scope, Utils) {
    $scope.anyLink = null;
    $scope.sportsLink = null;
    Utils.isImage('anyLink')
        .then(function (result) { $scope.anyLink = result });
    Utils.isImage('http://lorempixel.com/400/200/sports/1/')
        .then(function (result) { $scope.sportsLink = result });

    $scope.heading = "My Controller";
}

And then on your template, interact with $scope.anyLink or $scope.sportsLink

Sign up to request clarification or add additional context in comments.

3 Comments

Will this work dynamically? There could be hundreds of images to check, reading from a database
Thank you for your explanation
You should be able make a database request and then when it completes loop through the results, saving the results onto some array. You'll just want to make sure to do this once, when the controller is created, not every time the template is interpolated.
0

$scope.testImage is automatically watched by angular to see change of testImage. As a result you can stop infinite loop by using $scope.cache variable.

  $scope.testImage = function(src) {
    console.log('function triggered');
    if($scope.cache[src] == "result")
      return "result";
    Utils.isImage(src).then(function(result) {
             $scope.cache[src] = "result";
             return "result";
         });
    }; 

It was tested on your codepen.

1 Comment

This particular bit of code seems to have syntax errors... also, as $scope.cache is not set to "result", the function never runs, and it will never BE set.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.