Как показать объект в цикле AngularJS ng-repeat, только если существует его вложенное изображение?

Мой внешний интерфейс, управляемый AngulaJS, получает данные из местного JSON файл и позже переключится на API. Данные представляют собой список Project объекты с вложенными списками Image объекты. Я отображаю эти данные в цикле:

<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>

Но иногда изображение src неверно (ошибка 404). Было бы лучше пропустить такие проекты, где первое изображение (images[0]) не может быть найден. Как заставить скрипт пропустить нерелевантные объекты?


РЕДАКТИРОВАТЬ

У меня уже есть три ответа, но решения не работают, и я хочу точно объяснить проблему:

src Свойство изображений всегда установлено. Это не проблема. Это означает, что проверка, установлена ​​ли она или нет (как ng-show="projectItem._embedded.images[0].src != ''" или же ng-if="{{projectItem._embedded.images[0].src}}") не будет работать - не может работать.

Это не работает - src свойство установлено. Это неправильно (будет 404 ошибка), но она установлена ​​и projectItem._embedded.images[0].src != '' вернусь true и для "неактуальных" объектов.

4 ответа

Решение

Это хакерский способ сделать эту работу:

Чтобы избежать загрузки изображений, когда они бросают 404 ошибка или когда изображения являются недействительными,

Это должно быть внутри вашего контроллера. Эта функция проверяет, является ли URL-адрес изображения действительным / недействительным.

$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;
 };

Сейчас на виду:

Я инициирую объект под названием img={}; в ng-repeat,

Затем инициализация значения для этого индекса в ng-repeat в $scope.imageExists функция. Внутри этой функции, при успешной загрузке этого изображения, я устанавливаю 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

Таким образом, применяя его к вашему коду:

<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>

Поместите $scope.imageExists код сверху на ваш контроллер.

Вы можете использовать нг-если

<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>

Или вы также можете использовать ng-show/ng-hide, который просто не показывает элемент, но будет присутствовать в DOM.

Но будьте осторожны при использовании ng-if, поскольку он создает свою собственную область видимости.

РЕДАКТИРОВАТЬ: Если URL-адрес уже установлен, то один из способов - проверить, существует ли URL-адрес с помощью этого метода (или чего-либо подобного). JavaScript/jQuery проверяет битые ссылки
ng-if="UrlExists(projectItem._embedded.images[0].src)"

Вы можете создать свою собственную директиву об изображении:

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

Если изображение существует, директива вставит изображение в DOM. Если это не так, то вы можете проигнорировать это или вставить сообщение.

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>

        <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>
Другие вопросы по тегам