ngSrc 경로가 404로 해석되면 기본값으로 대체하는 방법이 있습니까?


129

내가 만들고있는 응용 프로그램은이 이미지가로드되기 전에 사용자가 4 가지 정보를 설정해야합니다. 이 이미지는 응용 프로그램의 중심 부분이므로 이미지 링크가 끊어지면 전체가 멍한 것처럼 보입니다. 404에서 다른 이미지를 사용하고 싶습니다.

어떤 아이디어? 이에 대한 사용자 지정 지시문 작성을 피하고 싶습니다.

비슷한 질문을 찾을 수 없다는 사실에 놀랐습니다. 특히 문서의 첫 번째 질문이 같은 경우에 특히 그렇습니다!

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


이것은 관련이있을 수 있습니다 : stackoverflow.com/q/13781685/1218080
— 홀로그램 원리

답변:


252

이미지 로딩 오류를보고 src를 교체하는 것은 매우 간단한 지시어입니다. (플 런커)

HTML :

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

자바 스크립트 :

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가 자동으로 오류를 삼킨다.
— Stephen Patten

2
빈 문자열이 모델에 유효하지 않은 경우 ng-src로 바인딩하는 표현식이 빈 문자열을 반환하지 않도록하십시오.
— Justin Lovero

의 지원 사용하도록 업데이트 스크립트 src에 대한 속성 err-src이미지 : plnkr.co/edit/b05WtghBOHkxKdttZ8q5
— 라이언 슈마허

@JustinLovero 나는 그것이 각도의 버그라고 생각하고 그것을보고했다. 문제는 값이 비어 있으면 ngSrc가 src 속성을 설정하지 않는다는 것입니다. 예를 들어 전화를 표시하고 이미지 URL이없는 아약스가있는 다른 전화를로드하는 경우 실제로 문제가 될 수 있습니다. 이전 전화의 이미지는 계속 표시되지만 오류 또는 자리 표시자가 더 적절할 것입니다. 예, 모델에서 처리 할 수 ​​있지만 오래된 이미지를 남기는 동작은 오류를 표시하는 것보다 더 잘못이라고 생각합니다.
— Jason Goemaat

@JasonGoemaat, 깨진 이미지를 텍스트로 바꾸려면 어떻게해야합니까?
— simeg

48

파티에 조금 늦었지만, 내가 구축하는 시스템에서 거의 같은 문제에 대한 해결책을 찾았습니다.

그러나 내 생각은 모든 이미지 img태그를 전 세계적으로 처리하는 것이 었습니다 .

나는 여기에 표시된 것과 HTML같은 불필요한 지시어로 내 고추를 피우고 싶지 않았습니다 err-src. 특히 동적 이미지의 경우 너무 늦을 때까지 이미지가 누락되었는지 알 수 없습니다. 오프-기회에 추가 지시문을 추가하면 이미지가 과도하게 보입니다.

대신 기존 img태그를 확장합니다 . 실제로 Angular 지시문이 전부입니다.

그래서 이것은 내가 생각해 낸 것입니다.

참고 :이를 위해서는 JQlite Angular뿐만 아니라 전체 JQuery 라이브러리가 있어야합니다..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
아주 좋은 해결책! 이걸 맨 위로 투표합시다!
— Matthijs

1
이것은 내가 말해야 할 매우 아름답습니다. 실제로 해결되지 않으면 이미지가 전혀 표시되는 것을 원하지 않으므로 사용했습니다. element.css ( "display", "none"); 완전히 숨기려면
— 폼페이우스

1
nice :) 또는 element.remove ();를 사용하여 DOM에서 완전히 제거 할 수 있습니다. :)
— Darren Wainwright

잘 작동합니다, 감사합니다!
— ecorvo

솔루션을 약간 편집 했으므로 경로가 비어있을 때도 작동합니다. stackoverflow.com/a/35884288/2014288
— andrfas

21

Jason 솔루션을 확장하여로드 오류 또는 빈 소스 문자열의 두 경우를 모두 포착하려면 시계를 추가하면됩니다.

HTML :

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

자바 스크립트 :

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'와 같은지 여부를 오류 함수 내부에서 확인할 수 있습니다.
— user2899845

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를 사용하지 않고 문제를 해결하기 때문에 이것이 정답이라고 생각합니다.
— Gregra

10

이미지가 404이거나 이미지가 비어 있으면 지시문이 필요하지 않은 경우 다음과 같이 ng-src 필터를 사용할 수 있습니다. :)

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

2
아니요, p.image가 AJAX 호출에서 404를 반환하면이를 'true'로 취급하고 두 번째 img / no-image.png로 이동하지 않습니다.
— James Gentes

2
@JamesGentes-그것은 사실이 아닌 것 같습니다. 이 ng-src 사용은 표시된대로 정확하게 작동합니다. 그리고 훨씬 간단합니다.
— shanemgrey

@shaneveeg 감사합니다. 흥미 롭습니다. 백엔드가 다른지 궁금합니다. Express로 Node를 실행 중입니다. 아마 다르게 처리합니다.
— James Gentes

2
@JamesGentes-이전 의견 수정. OP는 모델이 반환 한 유효한 URI가있을 때 해결책을 찾고 있지만 따라 올 때 404를 찾습니다. 이 경우이 솔루션이 작동하지 않아 이미지가 깨집니다. 각도가 이미지 값에 대해 아무것도 반환하지 않으면 폴백을 올바르게 선택합니다.
— shanemgrey

Laravel을 사용하고 있으며 404, null 또는 비어있는 경우 나에게 완벽하게 작동합니다. 그러나 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
이 겨-SRC가 볼 수있는 반면이 문자열 (참 /의 거짓)로 "team.logo"를 평가할 때 {{team.logo}}이 사실로는 404를 반환하는 경우에도, 올
— 제임스 씨족


1

코드에서 대체 이미지를 선언 할 수없는 특별한 이유가 있습니까?

내가 이해하는 것처럼 이미지 소스에 대해 두 가지 가능한 경우가 있습니다.

  1. 정보 조각 <4 = 대체 이미지를 올바르게 설정하십시오.
  2. 정보를 올바르게 설정 == 4 = 생성 된 URL.

올바른 URL을 확인할 수없는 경우 대신로드 / 폴백 / 자리 표시 자 이미지 URL을 전달하십시오.

특정 시점에 표시 할 올바른 URL을 명시 적으로 선언했기 때문에 '누락 된'이미지가 없기 때문입니다.


죄송합니다. 4 개의 값이 모두 설정되어 있어도 URL은 여전히 ​​404 (사용자는 폴더를 추가 할 수 있음) 일 수 있습니다. 그 동안 모든 값이 올 때 URL의 응답 헤더를 확인하는 기능을 추가했습니다. 설정됩니다. 여전히 특별한 대우없이 이것을 처리하는 것이 좋을 것입니다. 나는 이것을 다시 보게 될 것입니다 :)
— will_hardin

1
쿨, 당신은 대답으로 표시하고 미래에 검색하는 사람에게 허용으로 표시해야합니다.
— Alex Osborn

1

http://angular-ui.github.io/에있는 것처럼 Angular UI Utils 'if statement'지시문을 사용하여 문제를 해결하고 싶을 것 입니다. 방금 똑같은 일을하기 위해 사용했습니다.

이것은 테스트되지 않았지만 다음과 같이 할 수 있습니다.

컨트롤러 코드 :

$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 속성을 사용할 수 있습니다.

컨트롤러 코드 :

$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, 값, VALUE3 및 VALUE4 각각 동일시 것으로 가정합니다 null/ false정보를 귀하의 4 개의 각 (의 부울 값도 따라서 불완전한 경우 true가 완료되면).

추신. AngularUI 프로젝트는 최근에 하위 프로젝트로 분류되었으며 ui-if현재 설명서 가 누락 된 것 같습니다 (아마도 패키지에있을 수 있습니다). 그러나 당신이 볼 수 있듯이 사용하는 것은 매우 간단하며, Angular UI 프로젝트에 Github '문제'를 기록하여 팀에게도 지적했습니다.

업데이트 : 핵심 AngularJS 코드에 통합되어 있기 때문에 AngularUI 프로젝트에서 'ui-if'가 누락되었습니다! 그러나 현재 '불안정한'것으로 표시된 v1.1.x에서만.


ng-if핵심 btw에 넣었습니다 (실수하지 않으면 1.1.5 기준).
— 홀로그램 원리

1

다음은 네이티브 자바 스크립트를 사용하여 얻은 솔루션입니다. 이미지가 깨 졌는지 확인하고 소스를 변경하는 경우를 대비하여 이미지에 클래스를 추가합니다.

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);
                }              
            });
            }
        }
    }
})();
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.