jika jalur ngSrc diselesaikan ke 404, apakah ada cara untuk mundur ke default?


129

Aplikasi yang saya bangun mengharuskan pengguna saya untuk mengatur 4 informasi sebelum gambar ini bahkan memiliki kesempatan untuk memuat. Gambar ini adalah bagian tengah dari aplikasi, sehingga tautan gambar yang rusak membuatnya tampak seperti semuanya borked. Saya ingin gambar lain menggantikan 404.

Ada ide? Saya ingin menghindari penulisan arahan khusus untuk ini.

Saya terkejut bahwa saya tidak dapat menemukan pertanyaan serupa, terutama ketika pertanyaan pertama dalam dokumen adalah sama!

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



Jawaban:


252

Ini adalah arahan yang cukup sederhana untuk melihat kesalahan memuat gambar dan mengganti 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);
        }
      });
    }
  }
});

Jika Anda ingin menampilkan gambar kesalahan ketika ngSrc kosong Anda dapat menambahkan ini (Plunker) :

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

Masalahnya adalah ngSrc tidak memperbarui atribut src jika nilainya kosong.


Berfungsi dengan baik jika url rusak (404), tetapi jika itu adalah string kosong ng-src diam-diam menelan kesalahan.
Stephen Patten

2
Jika string kosong tidak valid untuk model Anda, maka buatlah agar ekspresi yang Anda ikat dengan ng-src tidak mengembalikan string kosong.
Justin Lovero

Skrip yang diperbarui untuk mendukung penggunaan srcatribut untuk err-srcgambar: plnkr.co/edit/b05WtghBOHkxKdttZ8q5
Ryan Schumacher

@JustinLovero Saya menganggapnya bug di sudut dan melaporkannya. Masalahnya adalah ngSrc tidak akan mengatur atribut src jika nilainya kosong. Itu sebenarnya bisa menjadi masalah jika misalnya Anda menampilkan telepon dan memuat telepon lain dengan ajax yang hilang url gambar. Gambar ponsel lama akan terus ditampilkan, tetapi saya pikir kesalahan atau pengganti akan lebih tepat. Ya, Anda bisa mengatasinya dalam model Anda tetapi perilaku meninggalkan gambar lama, saya pikir, lebih salah daripada menampilkan kesalahan.
Jason Goemaat

@JasonGoemaat, bagaimana cara saya mengganti gambar yang rusak dengan teks?
simeg

48

Agak terlambat ke pesta, meskipun saya datang dengan solusi untuk masalah yang kurang lebih sama dalam sistem yang saya bangun.

Namun, ide saya adalah untuk menangani SETIAP imgtag gambar secara global.

Saya tidak ingin harus membumbui saya HTMLdengan arahan yang tidak perlu, seperti err-srcyang ditunjukkan di sini. Cukup sering, terutama dengan gambar dinamis, Anda tidak akan tahu jika hilang sampai terlambat. Menambahkan arahan ekstra pada kesempatan gambar hilang tampaknya berlebihan bagi saya.

Sebagai gantinya, saya memperpanjang imgtag yang ada - yang, sebenarnya, adalah apa yang dimaksud dengan arahan Angular.

Jadi - inilah yang saya pikirkan.

Catatan : Ini membutuhkan pustaka JQuery lengkap untuk hadir dan tidak hanya kapal JQlite Angular dengan karena kami menggunakan.error()

Anda dapat melihatnya beraksi di Plunker ini

Arahannya terlihat seperti ini:

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');
            });
        }
    }
});

Ketika kesalahan terjadi (yang akan terjadi karena gambar tidak ada atau tidak terjangkau dll) kami menangkap dan bereaksi. Anda dapat mencoba untuk mendapatkan ukuran gambar juga - jika mereka hadir pada gambar / gaya di tempat pertama. Jika tidak, maka tentukan diri Anda sebagai default.

Contoh ini menggunakan placehold.it untuk menampilkan gambar sebagai gantinya.

Sekarang SETIAP gambar, terlepas dari menggunakan srcatau dengan ng-srcsendirinya telah tertutup seandainya tidak ada yang memuat ...


2
solusi yang sangat bagus! mari kita pilih yang ini ke atas!
Matthijs

1
Ini cukup indah, harus saya katakan. Saya sebenarnya tidak ingin gambar ditampilkan sama sekali jika tidak diselesaikan, jadi saya menggunakan: element.css ("display", "none"); untuk menyembunyikannya sepenuhnya
Pompey

1
bagus :) atau Anda bisa menghapusnya dari DOM sama sekali, dengan element.remove (); :)
Darren Wainwright

Bagus sekali, terima kasih!
ecorvo

Diedit sedikit solusi Anda, sehingga berfungsi juga saat path kosong. stackoverflow.com/a/35884288/2014288
andrfas

21

Untuk memperluas solusi Jason untuk menangkap kedua kasus kesalahan pemuatan atau string sumber kosong, kita bisa menambahkan arloji.

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
Kode yang bagus, tetapi tampaknya terlalu banyak menambah jam tangan untuk apa yang dapat dengan mudah diperiksa ng-ifdalam template (string src kosong)
alonisser

Sepertinya Anda bisa mengganti ngSrc dengan direktif Anda sendiri dan mengatur bind on error untuk menggunakan errSrc alih-alih memiliki direktif errSrc terpisah jika itu yang Anda inginkan. Anda bisa menggunakan attrs.$observe('ngSrc', function(value) {...});, itulah yang ngSrc gunakan secara internal alih-alih $ watch
Jason Goemaat

Seluruh masalah dengan blank adalah karena ngSrc tidak memperbarui atribut src jika nilainya kosong, jadi jika Anda memiliki arahan Anda sendiri untuk mengganti ngSrc, maka itu tidak memerlukan pemeriksaan kosong.
Jason Goemaat

1
@ Sokono - Anda dapat memeriksa di dalam fungsi kesalahan apakah atribut 'src' saat ini sama dengan 'errSrc'.
user2899845

1
@BiswasKhayargoli - menambahkan panggilan untuk berhenti berlangganan, sehingga tidak akan memiliki biaya pemrosesan setelah pemuatan awal
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;
            });
        }
    };
});

dalam HTML:

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

Saya merasa ini harus menjadi jawaban yang diterima karena tidak menggunakan jQuery dan memecahkan masalah
Gregra

10

Jika gambar 404 atau gambar kosong nol apa pun yang tidak perlu direktif Anda cukup menggunakan filter ng-src seperti ini :)

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

2
Tidak, jika p.image mengembalikan 404 pada panggilan AJAX, itu akan memperlakukan itu sebagai 'benar' dan tidak beralih ke img kedua / no-image.png.
James Gentes

2
@ JamesGentes - Sepertinya bukan itu masalahnya. Penggunaan ng-src ini bekerja untuk saya persis seperti yang ditunjukkan. Dan itu jauh lebih sederhana.
shanemgrey

@shaneveeg terima kasih, itu menarik - Saya ingin tahu apakah ujung belakangnya yang berbeda. Saya menjalankan Node dengan Express, mungkin ini menangani secara berbeda.
James Gentes

2
@JamesGentes - Koreksi komentar saya sebelumnya. OP sedang mencari solusi ketika ada URI yang valid dikembalikan oleh model, tetapi 404 ketika diikuti. Dalam hal ini, solusi ini tidak berfungsi, itu menghasilkan gambar yang rusak. Jika sudut tidak mengembalikan apa pun untuk nilai gambar, ini dengan benar memilih mundur.
shanemgrey

Saya menggunakan Laravel dan berfungsi sempurna untuk saya jika 404, null atau kosong adalah kasusnya. tapi mungkin Express mengembalikan beberapa jenis kesalahan alih-alih respons kode seperti 404 jadi ya mungkin tergantung pada kerangka server
NeoNe

8

Saya menggunakan sesuatu seperti ini, tetapi mengasumsikan bahwa team.logo valid. Ini memaksa default jika "team.logo" tidak disetel atau kosong.

<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
Ini benar, karena mengevaluasi "team.logo" sebagai string (benar / salah) sedangkan ng-src akan melihat {{team.logo}} benar bahkan jika ia mengembalikan 404.
James Gentes


1

Apakah ada alasan khusus Anda tidak dapat mendeklarasikan gambar mundur dalam kode Anda?

Seperti yang saya mengerti, Anda memiliki dua kemungkinan kasus untuk sumber gambar Anda:

  1. Setel informasi dengan benar <4 = Gambar mundur.
  2. Setel informasi dengan benar == 4 = URL yang dihasilkan.

Saya pikir ini harus ditangani oleh aplikasi Anda - jika URL yang benar saat ini tidak dapat ditentukan, alih-alih berikan URL gambar loading / fallback / placeholder.

Alasannya adalah bahwa Anda tidak pernah memiliki gambar 'hilang', karena Anda telah secara eksplisit mendeklarasikan URL yang benar untuk ditampilkan kapan saja.


Maaf, saya harus mengklarifikasi bahwa meskipun semua 4 nilai diatur, URL masih bisa 404 (pengguna dapat menambahkan folder di sepanjang jalan.) Sementara itu saya telah menambahkan fungsi yang memeriksa tajuk respons URL ketika semua nilai diatur. Masih bagus untuk menangani ini tanpa perlakuan khusus, saya yakin saya akan menemukan ini lagi :)
will_hardin

1
Keren, Anda harus menunjukkan itu sebagai jawaban dan menandainya diterima oleh siapa pun yang mencari di masa depan.
Alex Osborn

1

Saya sarankan Anda mungkin menggunakan arahan UI Utils 'if statement' direktif untuk menyelesaikan masalah Anda, seperti yang ditemukan di http://angular-ui.github.io/ . Saya baru saja menggunakannya untuk melakukan hal yang persis sama.

Ini belum diuji, tetapi Anda dapat melakukan sesuatu seperti:

Kode pengontrol:

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

(atau lebih sederhana)

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

HTML dalam Tampilan: <img ui-if="showImage()" ng-src="images/{{data.value}}.jpg" />

Atau bahkan lebih sederhana, Anda bisa menggunakan properti lingkup:

Kode pengontrol:

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

HTML dalam Tampilan: <img ui-if="showImage" ng-src="images/{{data.value}}.jpg" />

Untuk gambar placeholder, cukup tambahkan <img>tag lain yang serupa tetapi tambahkan ui-ifparameter Anda sebelumnya dengan tanda seru ( !), dan buat ngSrc memiliki path ke gambar placeholder, atau cukup gunakan srctag sesuai HTML biasa.

misalnya. <img ui-if="!showImage" src="images/placeholder.jpg" />

Jelas, semua contoh kode di atas mengasumsikan bahwa masing-masing value1, value2, value3 dan value4 akan sama dengan null/ falseketika masing-masing dari 4 informasi Anda tidak lengkap (dan dengan demikian juga dengan nilai boolean trueketika mereka selesai).

PS. Proyek AngularUI baru-baru ini telah dipecah menjadi sub-proyek, dan dokumentasi untuk ui-iftampaknya hilang saat ini (mungkin ada dalam paket di suatu tempat). Namun, cukup mudah untuk digunakan seperti yang Anda lihat, dan saya telah mencatat 'masalah' Github pada proyek UI Angular untuk menunjukkannya kepada tim juga.

UPDATE: 'ui-if' hilang dari proyek AngularUI karena sudah terintegrasi ke dalam kode inti AngularJS! Namun hanya pada v1.1.x, yang saat ini ditandai sebagai 'tidak stabil'.


ng-ifmembuatnya menjadi btw inti (pada 1.1.5 jika saya tidak salah).
asas holografik

1

Inilah solusi yang saya buat dengan menggunakan javascript asli. Saya memeriksa jika gambar rusak lalu menambahkan kelas ke gambar untuk berjaga-jaga dan mengubah sumber.

Saya mendapat bagian dari jawaban saya dari jawaban 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

Datang dengan solusi saya sendiri. Ini menggantikan gambar baik jika src atau ngSrc kosong, dan jika img mengembalikan 404.

(garpu solusi @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

Ini hanya akan memungkinkan untuk mengulang dua kali, untuk memeriksa apakah ng-src tidak ada lagi menggunakan err-src, ini mencegah pengulangan berlanjut.

(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);
                }              
            });
            }
        }
    }
})();
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.