ถ้าเส้นทาง ngSrc เปลี่ยนเป็น 404 มีวิธีเปลี่ยนกลับเป็นค่าเริ่มต้นหรือไม่?


129

แอปพลิเคชันที่ฉันกำลังสร้างต้องการให้ผู้ใช้ตั้งค่าข้อมูล 4 ชิ้นก่อนที่ภาพนี้จะมีโอกาสโหลดได้ รูปภาพนี้เป็นชิ้นส่วนกึ่งกลางของแอปพลิเคชันดังนั้นลิงก์รูปภาพที่เสียจึงทำให้ดูเหมือนว่าสิ่งทั้งหมดถูกบอร์ก ฉันต้องการให้มีภาพอื่นแทนบน 404

ความคิดใด ๆ ? ฉันต้องการหลีกเลี่ยงการเขียนคำสั่งที่กำหนดเองสำหรับสิ่งนี้

ฉันแปลกใจที่ไม่พบคำถามที่คล้ายกันโดยเฉพาะอย่างยิ่งเมื่อคำถามแรกในเอกสารเป็นคำถามเดียวกัน!

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


สิ่งนี้อาจเกี่ยวข้อง: stackoverflow.com/q/13781685/1218080
หลักการโฮโลแกรม

ที่เกี่ยวข้อง: stackoverflow.com/questions/27549134/…
user2954463

คำตอบ:


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 จะกลืนข้อผิดพลาดอย่างเงียบ ๆ
Stephen Patten

2
หากสตริงว่างไม่ถูกต้องสำหรับโมเดลของคุณให้กำหนดให้นิพจน์ที่คุณเชื่อมโยงกับ ng-src ไม่ส่งคืนสตริงว่าง
Justin Lovero

อัปเดตสคริปต์เพื่อรองรับการใช้srcแอตทริบิวต์สำหรับerr-srcรูปภาพ: plnkr.co/edit/b05WtghBOHkxKdttZ8q5
Ryan Schumacher

@JustinLovero ฉันคิดว่ามันเป็นข้อผิดพลาดในเชิงมุมและรายงานมัน ปัญหาคือ ngSrc จะไม่ตั้งค่าแอตทริบิวต์ src หากค่าว่างเปล่า นั่นอาจเป็นปัญหาได้หากคุณกำลังแสดงโทรศัพท์และโหลดโทรศัพท์เครื่องอื่นที่มี ajax ซึ่งไม่มี url รูปภาพ รูปภาพของโทรศัพท์เครื่องเก่าจะยังคงแสดงต่อไป แต่ฉันคิดว่าข้อผิดพลาดหรือตัวยึดจะเหมาะสมกว่า ใช่คุณสามารถจัดการกับมันในโมเดลของคุณได้ แต่ฉันคิดว่าพฤติกรรมของการทิ้งภาพเก่านั้นผิดมากกว่าการแสดงข้อผิดพลาด
Jason Goemaat

@ 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
ทางออกที่ดีมาก! มาโหวตอันนี้กันเถอะ!
Matthijs

1
สวยมากเลยทีเดียวต้องขอบอก ที่จริงฉันไม่ต้องการให้ภาพใด ๆ แสดงเลยถ้ามันไม่สามารถแก้ไขได้ฉันจึงใช้: element.css ("display", "none"); เพื่อซ่อนมันทั้งหมด
Pompey

1
ดี :) หรือคุณสามารถลบออกจาก DOM ทั้งหมดด้วย element.remove (); :)
Darren Wainwright

ใช้งานได้ดีขอบคุณ!
ecorvo

แก้ไขโซลูชันของคุณเล็กน้อยดังนั้นจึงใช้งานได้เมื่อเส้นทางว่างเปล่า stackoverflow.com/a/35884288/2014288
andrfas

21

หากต้องการขยายโซลูชัน Jason เพื่อตรวจจับทั้งสองกรณีของข้อผิดพลาดในการโหลดหรือสตริงซอร์สว่างเราสามารถเพิ่มนาฬิกา

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" หรือไม่
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 ส่งคืน 404 ในการเรียก AJAX มันจะถือว่าเป็น 'จริง' และไม่ย้ายไปที่ img / no-image.png ที่สอง
James Gentes

2
@JamesGentes - ดูเหมือนจะไม่เป็นเช่นนั้น การใช้ ng-src นี้ใช้ได้ผลกับฉันทุกประการตามที่แสดง และมันง่ายกว่ามาก
shanemgrey

@shaneveeg ขอบคุณที่น่าสนใจ - ฉันสงสัยว่าส่วนหลังแตกต่างกันหรือไม่ ฉันใช้งาน Node ด้วย Express บางทีมันอาจจะจัดการต่างออกไป
James Gentes

2
@JamesGentes - แก้ไขความคิดเห็นก่อนหน้าของฉัน OP กำลังมองหาวิธีแก้ปัญหาเมื่อมี 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" เป็นสตริง (จริง / เท็จ) ในขณะที่ ng-src จะเห็นว่า {{team.logo}} เป็นจริงแม้ว่าจะส่งคืน 404 ก็ตาม
James Gentes

2

คุณไม่จำเป็นต้องมีมุมสำหรับสิ่งนั้นหรือแม้แต่ CSS หรือ JS หากคุณต้องการคุณสามารถรวมคำตอบนี้ (เชื่อมโยง) เป็นคำสั่งง่ายๆเพื่อให้ง่ายขึ้นเช่นหรือบางอย่าง แต่เป็นกระบวนการที่ค่อนข้างง่าย ... เพียงแค่ห่อไว้ในแท็กวัตถุ ...

วิธีซ่อนไอคอนที่เสียภาพโดยใช้ CSS / HTML เท่านั้น (ไม่มี js)


1

มีเหตุผลเฉพาะที่คุณไม่สามารถประกาศภาพสำรองในโค้ดของคุณได้หรือไม่?

ตามที่ฉันเข้าใจคุณมีสองกรณีที่เป็นไปได้สำหรับแหล่งที่มาของภาพ:

  1. กำหนดชิ้นส่วนข้อมูลอย่างถูกต้อง <4 = รูปภาพสำรอง
  2. ตั้งค่าข้อมูลอย่างถูกต้อง == 4 = URL ที่สร้างขึ้น

ฉันคิดว่าแอปของคุณควรจัดการสิ่งนี้ - หากไม่สามารถระบุ URL ที่ถูกต้องได้ในขณะนี้ให้ส่ง URL ภาพโหลด / ทางเลือก / ตัวยึดแทน

เหตุผลก็คือคุณไม่เคยมีรูปภาพที่ 'ขาดหายไป' เนื่องจากคุณได้ประกาศ URL ที่ถูกต้องอย่างชัดเจนเพื่อแสดง ณ เวลาใดเวลาหนึ่ง


ขออภัยฉันควรชี้แจงว่าแม้ว่าจะตั้งค่าทั้ง 4 ค่าแล้ว แต่ URL ก็ยังสามารถเป็น 404 ได้ (ผู้ใช้สามารถเพิ่มโฟลเดอร์ได้ระหว่างทาง) ในระหว่างนี้ฉันได้เพิ่มฟังก์ชันที่ตรวจสอบส่วนหัวการตอบกลับของ URL เมื่อค่าทั้งหมด มีการตั้งค่า. ยังคงเป็นการดีที่จะจัดการกับสิ่งนี้โดยไม่ต้องดูแลเป็นพิเศษฉันพนันได้เลยว่าฉันจะเจอสิ่งนี้อีกครั้ง :)
will_hardin

1
เจ๋งมากคุณควรแสดงเป็นคำตอบและทำเครื่องหมายว่ายอมรับสำหรับทุกคนที่ค้นหาในอนาคต
Alex Osborn

1

ฉันขอแนะนำว่าคุณอาจต้องการใช้คำสั่ง 'if statement' ของ Angular UI Utils เพื่อแก้ปัญหาของคุณดังที่พบในhttp://angular-ui.github.io/ 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แท็กตาม 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ทำให้มันกลายเป็นแกน 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.