0

My AngulaJS driven frontend gets the data from a local JSON file and will later switch to an API. The data is a list of Project objects with nested lists of Image objects. I'm displaying this data in a loop:

<div id="projects" ng-app="portfolio">
    <div id="projectsList" ng-controller="ProjectsListController as projectsList">
        <div class="projectItem" ng-repeat="projectItem in projectsList.projectsListData._embedded.projects">
            <div class="project-image">
                <img
                    ng-src="{{projectItem._embedded.images[0].src}}"
                    title="{{projectItem.title}} - {{projectItem._embedded.images[0].title}}"
                    alt="{{projectItem.title}} - {{projectItem._embedded.images[0].title}}"
                />
            </div>
        </div>
    </div>
</div>

But sometimes the image src is invalid (error 404). It would be better to skip such projects, where the first image (images[0]) cannot be found. How to make the script skip the irrelevant objects?


EDIT

I've already got three answers, but the solutions don't work and I want to explain the problem exactly:

The src property of the images is alwys set. It's not the problem. That means, that checking if it's set or not (like ng-show="projectItem._embedded.images[0].src != ''" or ng-if="{{projectItem._embedded.images[0].src}}") will not work -- cannot work.

It doesn't work -- the src property is set. It's wrong (will cuase the 404 error), but it's set and projectItem._embedded.images[0].src != '' will return true for the "irrelevant" objects as well.

enter image description here

enter image description here

1

4 Answers 4

2

This is a hacky way of making this work:

To avoid loading images when they throw 404 error or when the images are invalid,

This must be inside your controller. This function checks whether the image URL is valid/invalid.

$scope.imageExists = function(image, object, index) {
    var img = new Image();
    img.onload = function() {
      object[index] = true;
      $scope.$apply();
    }; 
    img.onerror = function() {
      return false;
    };
    img.src = image;
 };

Now in View:

I'm initiating an object called img={}; in the ng-repeat.

Then initializing the value for that index in ng-repeat to $scope.imageExists function. Inside that function, on success of that image load, am setting img[index]= true.

<div ng-repeat="image in images" ng-init="img = {}">
   <img ng-src="{{image}}" ng-init="img[$index] = imageExists(image, img, $index)" ng-show="img[$index]">
</div>

DEMO

So applying it to your code:

<div id="projects" ng-app="portfolio">
    <div id="projectsList" ng-controller="ProjectsListController as projectsList">
        <div class="projectItem" ng-repeat="projectItem in projectsList.projectsListData._embedded.projects"  ng-init="img = {}">
            <div class="project-image" ng-init="img[$index] = imageExists(projectItem._embedded.images[0].src, img, $index)" ng-show="img[$index]">
                <img
                    ng-src="{{projectItem._embedded.images[0].src}}"
                    title="{{projectItem.title}} - {{projectItem._embedded.images[0].title}}"
                    alt="{{projectItem.title}} - {{projectItem._embedded.images[0].title}}"
                />
            </div>
        </div>
    </div>
</div>

Place the $scope.imageExists code from above to your controller.

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

Comments

1

You can use ng-if

<div class="projectItem" ng-repeat="projectItem in projectsList.projectsListData._embedded.projects" ng-if="{{projectItem._embedded.images[0].src}}">
            <div class="project-image">
                <img
                    ng-src="{{projectItem._embedded.images[0].src}}"
                    title="{{projectItem.title}} - {{projectItem._embedded.images[0].title}}"
                    alt="{{projectItem.title}} - {{projectItem._embedded.images[0].title}}"
                />
            </div>
        </div>
    </div>

Or you can also use ng-show/ng-hide which just doesn't show the element but would be present in DOM.

But be careful when you use ng-if as it creates its own scope.

EDIT: If the url is already set then one way is to test if the url exists using this method (or anything like this) JavaScript/jQuery check broken links , and
ng-if="UrlExists(projectItem._embedded.images[0].src)"

1 Comment

It doesn't work -- the src property is set. It's wrong (will cuase the 404 error), but it's set and projectItem._embedded.images[0].src != '' will return true for the "irrelevant" objects as well.
0
        <div class="project-image" ng-if="projectItem._embedded.images[0].src != ''">
            <img
                ng-src="{{projectItem._embedded.images[0].src}}"
                title="{{projectItem.title}} - {{projectItem._embedded.images[0].title}}"
                alt="{{projectItem.title}} - {{projectItem._embedded.images[0].title}}"
            />
        </div>

1 Comment

It doesn't work -- the src property is set. It's wrong (will cuase the 404 error), but it's set and projectItem._embedded.images[0].src != '' will return true for the "irrelevant" objects as well.
0

You could create your own image directive:

<my-image src="http://someimageurl"></my-image>

If the image exists, the directive will insert the image into the DOM. If it does not, then you can ignore it, or insert a message.

var app = angular.module('app', []);
app.directive('myImage', function() {
  return {
    restrict: 'E',
    replace:true,
    link: function(scope, element, attr) {
      var image = new Image();
      image.onload = function() {
         element.append(image);
      }
      image.onerror = function() {
         element.html('Something went wrong or the image does not exist...');
      }
      image.src = attr.src;
    }
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
  <my-image src="https://www.google.ca/images/srpr/logo11w.png" />
  
  <my-image src="https://server/images/doesnotexist.png" />
</div>

1 Comment

Thank you for your answer! It works for the img tag, bun in my case I want to enable/disable the whole container wrapping the image.

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.