якщо шлях до ngSrc дорівнює 404, чи існує спосіб повернення до замовчування?


129

Додаток, який я будую, вимагає від мого користувача встановити 4 фрагменти інформації, перш ніж це зображення навіть матиме можливість завантаження. Це зображення є центральною частиною програми, тож розірване посилання на зображення робить його схожим на те, що вся справа захищена. Я хотів би, щоб інше зображення зайняло своє місце на 404.

Будь-які ідеї? Я хотів би уникати написання спеціальної директиви для цього.

Я був здивований, що не зміг знайти подібне запитання, особливо коли перше запитання в документах одне й те саме!

http://docs.angularjs.org/api/ng.directive:ngSrc



Відповіді:


252

Це досить проста директива - спостерігати за помилкою завантаження зображення та заміною src. (Plunker)

Html:

<img ng-src="smiley.png" err-src="http://google.com/favicon.ico" />

Javascript:

var app = angular.module("MyApp", []);

app.directive('errSrc', function() {
  return {
    link: function(scope, element, attrs) {
      element.bind('error', function() {
        if (attrs.src != attrs.errSrc) {
          attrs.$set('src', attrs.errSrc);
        }
      });
    }
  }
});

Якщо ви хочете відобразити зображення помилки, коли ngSrc порожній, ви можете додати це (Plunker) :

attrs.$observe('ngSrc', function(value) {
  if (!value && attrs.errSrc) {
    attrs.$set('src', attrs.errSrc);
  }
});

Проблема полягає в тому, що ngSrc не оновлює атрибут src, якщо значення порожнє.


Добре працює, якщо URL-адресу порушено (404), але якщо це порожній рядок ng-src мовчки ковтає помилку.
Стівен Паттен

2
Якщо порожня рядок не відповідає вашій моделі, тоді зробіть її так, щоб вираз, для якого ви зв'язуєтесь з ng-src, не повертав порожню рядок.
Джастін Ловеро

Оновлений сценарій для підтримки використання srcатрибута для err-srcзображення: plnkr.co/edit/b05WtghBOHkxKdttZ8q5
Ryan Schumacher

@JustinLovero Я вважаю це помилкою у кутовій і повідомив про це. Проблема полягає в тому, що ngSrc не встановить атрибут src, якщо значення порожнє. Це насправді може бути проблемою, якщо, наприклад, ви показуєте телефон і завантажуєте інший телефон з ajax, у якому відсутня URL-адреса зображення. Зображення старого телефону й надалі відображатиметься, але я думаю, що помилка чи заповнювач місця були б більш доречними. Так, ви могли б впоратися з цією моделлю, але поведінка залишати старе зображення є, я думаю, більш помилковим, ніж відображення помилки.
Джейсон Джейм

@JasonGoemaat, як би я міг замінити розбите зображення текстом?
simeg

48

Трохи запізнюючись на партію, хоча я вирішив більш-менш те саме питання в системі, яку будую.

Моя ідея полягала в тому, щоб обробляти КОЖЕН imgтег зображень у всьому світі.

Мені не хотілося пересипати HTMLнепотрібними директивами, такими, як err-srcпоказано тут. Досить часто, особливо з динамічними зображеннями, ви не дізнаєтесь, чи не вистачає вона, поки не пізно. Додавання додаткових директив щодо випадкових випадків, коли зображення відсутнє, мені здається непосильним.

Натомість я розширюю існуючий imgтег - який насправді полягає у тому, що стосується кутових директив.

Отже - ось що я придумав.

Примітка . Для цього потрібна повна бібліотека JQuery, а не тільки кутові JQlite Angular, тому що ми їх використовуємо.error()

Ви можете бачити це в дії на цьому Plunker

Директива виглядає приблизно так:

app.directive('img', function () {
    return {
        restrict: 'E',        
        link: function (scope, element, attrs) {     
            // show an image-missing image
            element.error(function () {
                var w = element.width();
                var h = element.height();
                // using 20 here because it seems even a missing image will have ~18px width 
                // after this error function has been called
                if (w <= 20) { w = 100; }
                if (h <= 20) { h = 100; }
                var url = 'http://placehold.it/' + w + 'x' + h + '/cccccc/ffffff&text=Oh No!';
                element.prop('src', url);
                element.css('border', 'double 3px #cccccc');
            });
        }
    }
});

При виникненні помилки (що може бути через те, що зображення не існує або недоступне тощо), ми фіксуємо та реагуємо. Ви також можете спробувати отримати розміри зображень - якщо вони в першу чергу були присутні на зображенні / стилі. Якщо ні, то встановіть собі за замовчуванням.

У цьому прикладі використовується placehold.it, щоб зображення відображалось замість цього.

Тепер КОЖНЕ зображення, незалежно від використання srcчи ng-srcпокриття, якщо нічого не завантажується ...


2
дуже приємне рішення! давайте проголосуємо цього до вершини!
Маттійс

1
Це дуже красиво, я мушу сказати. Я насправді не хочу, щоб жодне зображення відображалося взагалі, якщо воно не вирішується, тому я використовував: element.css ("показ", "немає"); щоб просто приховати це повністю
Помпей

1
приємно :) або ви можете просто видалити його з DOM взагалі, з element.remove (); :)
Даррен Уейнрайт

Чудово працює, дякую!
ecorvo

Трохи відредагував ваше рішення, тож воно працює і тоді, коли шлях порожній. stackoverflow.com/a/35884288/2014288
andrfas

21

Щоб розширити рішення Джейсона, щоб виявити обидва випадки помилки завантаження або порожній рядок джерела, ми можемо просто додати годинник.

Html:

<img ng-src="smiley.png" err-src="http://google.com/favicon.ico" />

Javascript:

var app = angular.module("MyApp", []);

app.directive('errSrc', function() {
  return {
    link: function(scope, element, attrs) {

      var watcher = scope.$watch(function() {
          return attrs['ngSrc'];
        }, function (value) {
          if (!value) {
            element.attr('src', attrs.errSrc);  
          }
      });

      element.bind('error', function() {
        element.attr('src', attrs.errSrc);
      });

      //unsubscribe on success
      element.bind('load', watcher);

    }
  }
});

2
Хороший код, але, здається, зайвим є додавання годинника на те, що можна легко перевірити ng-ifу шаблоні (порожній рядок src)
alonisser

Здається, ви могли просто замінити ngSrc власною директивою, і він встановив прив'язку помилок до використання errSrc, а не окремої директиви errSrc, якщо це те, що ви хочете. Ви можете використовувати attrs.$observe('ngSrc', function(value) {...});, ось що ngSrc використовує внутрішньо замість $ watch
Jason Goemaat

Вся проблема з пробілами полягає в тому, що ngSrc не оновлює атрибут src, якщо значення порожнє, тому, якщо у вас була власна директива щодо заміни ngSrc, вона не потребує пустої перевірки.
Jason Goemaat

1
@Pokono - ви можете перевірити всередині функції помилок, чи поточний атрибут 'src' такий, як 'errSrc'.
користувач2899845

1
@BiswasKhayargoli - додав дзвінок, щоб скасувати підписку, тому у нього не буде жодної вартості обробки після початкового завантаження
user2899845

11
App.directive('checkImage', function ($q) {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            attrs.$observe('ngSrc', function (ngSrc) {
                var deferred = $q.defer();
                var image = new Image();
                image.onerror = function () {
                    deferred.resolve(false);
                    element.attr('src', BASE_URL + '/assets/images/default_photo.png'); // set default image
                };
                image.onload = function () {
                    deferred.resolve(true);
                };
                image.src = ngSrc;
                return deferred.promise;
            });
        }
    };
});

в HTML:

<img class="img-circle" check-image ng-src="{{item.profileImg}}" />

Я вважаю, що це має бути прийнятою відповіддю, оскільки він не використовує jQuery і вирішує проблему
Грегра

10

Якщо зображення 404 або зображення порожнє порожнє, все, що немає необхідності в директивах, ви можете просто використовувати фільтр ng-src, як це :)

<img ng-src="{{ p.image || 'img/no-image.png' }}" />

2
Ні, якщо p.image повертає 404 під час виклику AJAX, він вважатиме це "справжнім" і не перейде до другого img / no-image.png.
Джеймс Гентес

2
@JamesGentes - Схоже, це не так. Це використання ng-src працює для мене саме так, як показано. І це набагато простіше.
shanemgrey

@shaneveeg спасибі, це цікаво - мені цікаво, чи є задній кінець чим відрізняється. Я запускаю Node за допомогою Express, можливо, він обробляє його інакше.
Джеймс Гентес

2
@JamesGentes - виправлення мого попереднього коментаря. ОП шукає рішення, коли є дійсний URI, повернутий моделлю, але 404, коли він дотримується. У такому випадку це рішення не працює, це призводить до порушення зображення. Якщо кутовий не повертає нічого для значення зображення, це правильно вибирає резервний запас.
shanemgrey

Я використовую Laravel, і він ідеально підходить для мене, якщо справа 404, нульова або порожня. але, можливо, Express повертає якусь помилку замість кодової відповіді на зразок 404, так так, ймовірно, залежить від серверної бази
NeoNe

8

Я використовую щось подібне, але передбачається, що team.logo є дійсним. Він примушує за замовчуванням, якщо "team.logo" не встановлений або порожній.

<img ng-if="team.logo" ng-src="https://api.example.com/images/{{team.logo}}">
<img ng-hide="team.logo" ng-src="img/default.png">

2
Це правильно, оскільки він оцінює "team.logo" як рядок (true / false), тоді як ng-src побачить {{team.logo}} як істинне, навіть якщо він поверне 404.
Джеймс Гентес

2

Для цього вам не потрібні кутові або навіть CSS або JS. Якщо ви хочете, ви можете загорнути цю відповідь (зв'язану) у просту директиву, щоб зробити її простішою, як-небудь чи що-небудь, але це досить простий процес ... просто загорніть її в тег об'єкта ...

Як приховати зображення зламаного значка за допомогою лише CSS / HTML (без js)


1

Чи є певна причина, що ви не можете оголосити резервне зображення у своєму коді?

Як я розумію, у вас є два можливі випадки для вашого джерела зображення:

  1. Правильно встановити фрагменти інформації <4 = Звольне зображення.
  2. Правильно встановити фрагменти інформації == 4 = Генерована URL-адреса.

Я думаю, що це має вирішити ваш додаток - якщо правильну URL-адресу наразі неможливо визначити, замість цього введіть URL-адресу зображення для завантаження / запасного / заповнення.

Міркування полягає в тому, що у вас ніколи не виникає "пропущеного" зображення, оскільки ви явно оголосили правильну URL-адресу для відображення в будь-який момент часу.


Вибачте, я мав би уточнити, що навіть якщо встановлено всі 4 значення, URL-адреса може все-таки 404 (користувач може додавати папки попутно.) Тим часом я додав функцію, яка перевіряє заголовки відповідей URL-адреси, коли всі значення встановлюються. Все одно було б непогано впоратися з цим без спеціального лікування,
сподіваюся

1
Класно, ви повинні показати це як відповідь і позначити його як прийняте для всіх, хто шукає в майбутньому.
Алекс Осборн

1

Я пропоную вам скористатися директивою Angular UI Utils 'if statement' для вирішення вашої проблеми, як це знайдено на веб-сайті http://angular-ui.github.io/ . Я щойно використовував це, щоб зробити саме те саме.

Це не перевірено, але ви можете зробити щось на кшталт:

Код контролера:

$scope.showImage = function () {
    if (value1 && value2 && value3 && value4) { 
        return true;
    } else {
        return false;
    }
};

(або простіше)

$scope.showImage = function () {
    return value1 && value2 && value3 && value4;
};

HTML у перегляді: <img ui-if="showImage()" ng-src="images/{{data.value}}.jpg" />

Або навіть простіше, ви можете просто використовувати властивість області застосування:

Код контролера:

$scope.showImage = value1 && value2 && value3 && value4;

HTML у перегляді: <img ui-if="showImage" ng-src="images/{{data.value}}.jpg" />

Для зображення заповнювача просто додайте ще один подібний <img>тег, але додайте ui-ifпараметр !позначкою знак оклику ( ) та зробіть, що ngSrc має шлях до зображення заповнювача, або просто використовуйте srcтег відповідно до звичайного ol 'HTML.

напр. <img ui-if="!showImage" src="images/placeholder.jpg" />

Очевидно, що всі вищевказані зразки коду припускають, що кожен із значень1, значення2, значення3 та значення4 буде дорівнювати null/ falseколи кожен з ваших 4 фрагментів інформації буде неповним (і, таким чином, також булевим значенням, trueколи вони повні).

PS. Нещодавно проект AngularUI був розбитий на підпроекти, і документація на ui-ifданий момент, здається, відсутня (хоча, мабуть, в пакеті десь). Однак, як бачите, це досить просто, і я зареєстрував «проблему» Github у проекті Angular UI, щоб також вказати на команду.

ОНОВЛЕННЯ: 'ui-if' відсутній у проекті AngularUI, оскільки він був інтегрований в основний код AngularJS! Тільки станом на v1.1.x, яка наразі позначена як "нестабільна".


ng-ifвніс це в core btw (як на 1.1.5, якщо я не помиляюся).
голографічний принцип

1

Ось рішення, яке я придумав, використовуючи нативний JavaScript. Я перевіряю, чи зображення порушено, тоді додаю клас до зображення на всякий випадок і змінюю джерело.

Я отримав частину своєї відповіді з відповіді Quora http://www.quora.com/How-do-I-use-JavaScript-to-find-if-an-image-is-broken

app.directive('imageErrorDirective', function () {
    return {
        restrict: 'A',
        link: function (scope, element, attrs) {
            element[0].onerror = function () {
                element[0].className = element[0].className + " image-error";
                element[0].src = 'http://img3.wikia.nocookie.net/__cb20140329055736/pokemon/images/c/c9/702Dedenne.png';
            };
        }
    }
});

0

Придумав власне рішення. Він замінює зображення як src або ngSrc порожнім, так і якщо img повертає 404.

(вилка розчину @Darren)

directive('img', function () {
return {
    restrict: 'E',        
    link: function (scope, element, attrs) {   
        if((('ngSrc' in attrs) && typeof(attrs['ngSrc'])==='undefined') || (('src' in attrs) && typeof(attrs['src'])==='undefined')) {
            (function () {
                replaceImg();
            })();
        };
        element.error(function () {
            replaceImg();
        });

        function replaceImg() {
            var w = element.width();
            var h = element.height();
            // using 20 here because it seems even a missing image will have ~18px width 
            // after this error function has been called
            if (w <= 20) { w = 100; }
            if (h <= 20) { h = 100; }
            var url = 'http://placehold.it/' + w + 'x' + h + '/cccccc/ffffff&text=No image';
            element.prop('src', url);
        }
    }
}
});

0

Це дозволить циклічно циклічити лише двічі, щоб перевірити, чи не існує ng-src, використовуйте err-src, це запобігає продовженню циклу.

(function () {
    'use strict';
    angular.module('pilierApp').directive('errSrc', errSrc);

    function errSrc() {
        return {
            link: function(scope, element, attrs) {
             element.error(function () {
                // to prevent looping error check if src == ngSrc
                if (element.prop('src')==attrs.ngSrc){
                     //stop loop here
                     element.prop('src', attrs.errSrc);
                }              
            });
            }
        }
    }
})();
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.