якщо шлях до 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.