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

automatix
  • 14,018
  • 26
  • 105
  • 230
  • I've come up with an approach for this. Check if its useful for you. Demo : http://jsbin.com/kedirofako/1/edit?html,js,output – mohamedrias Apr 04 '15 at 11:51

4 Answers4

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.

mohamedrias
  • 18,326
  • 2
  • 38
  • 47
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)"

Community
  • 1
  • 1
Srinath Mandava
  • 3,384
  • 2
  • 24
  • 37
  • 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. – automatix Apr 04 '15 at 11:33
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>
Hardy
  • 542
  • 4
  • 10
  • 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. – automatix Apr 04 '15 at 11:32
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>
Michael Kang
  • 52,003
  • 16
  • 103
  • 135
  • 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. – automatix Apr 04 '15 at 13:29