bir ngSrc yolu 404'e dönüşürse, varsayılana geri dönmenin bir yolu var mı?


129

Oluşturmakta olduğum uygulama, kullanıcımın bu görüntünün yükleme şansı olmadan önce 4 parça bilgi ayarlamasını gerektiriyor. Bu görüntü, uygulamanın merkez parçasıdır, bu nedenle kopuk görüntü bağlantısı, her şey dallanmış gibi görünmesini sağlar. 404'te başka bir görüntünün yerini almasını istiyorum.

Herhangi bir fikir? Bunun için özel bir yönerge yazmaktan kaçınmak istiyorum.

Özellikle dokümanlardaki ilk soru aynı olduğunda benzer bir soru bulamadığıma şaşırdım!

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



Yanıtlar:


252

Bir görüntüyü yüklerken bir hata olup olmadığını izlemek ve src'yi değiştirmek oldukça basit bir direktiftir. (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 boşken hata görüntüsünü görüntülemek istiyorsanız, bunu ekleyebilirsiniz (Plunker) :

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

Sorun, değer boşsa ngSrc'nin src niteliğini güncellememesidir.


Url bozuksa (404) iyi çalışır, ancak boş bir dizeyse ng-src hatayı sessizce yutar.
Stephen Patten

2
Modeliniz için boş bir dize geçerli değilse, onu ng-src ile bağladığınız ifade boş bir dize döndürmeyecek şekilde yapın.
Justin Lovero

Görüntü srciçin öznitelik kullanımını desteklemek için güncellenmiş komut dosyası err-src: plnkr.co/edit/b05WtghBOHkxKdttZ8q5
Ryan Schumacher

@JustinLovero Bunu bir açısal hata olarak görüyorum ve rapor ettim. Sorun, değer boşsa ngSrc'nin src özelliğini ayarlamamasıdır. Örneğin bir telefon görüntülüyorsanız ve bir resim url'si eksik ajax ile başka bir telefon yüklüyorsanız, bu aslında bir sorun olabilir. Eski telefonun görüntüsü görüntülenmeye devam edecek, ancak bir hata veya yer tutucunun daha uygun olacağını düşünüyorum. Evet, bunu modelinizde halledebilirsiniz, ancak eski bir görüntüyü bırakma davranışı, bence, bir hata göstermekten daha yanlış.
Jason Goemaat

@JasonGoemaat, bozuk görüntüyü metinle değiştirmek için nasıl yapmalıyım?
simeg

48

Partiye biraz geç olsa da, oluşturduğum bir sistemde aşağı yukarı aynı soruna bir çözüm buldum.

Benim fikrim, HER görüntü imgetiketini küresel olarak ele almaktı .

Burada gösterilenler HTMLgibi gereksiz direktifleri benimsemek zorunda kalmak istemedim err-src. Çoğu zaman, özellikle dinamik görüntülerde, çok geç olana kadar eksik olup olmadığını bilemezsiniz. Şans eseri bir görüntünün eksik olduğuna dair ekstra yönergeler eklemek bana aşırı geliyor.

Bunun yerine, mevcut imgetiketi genişletiyorum - ki bu, Angular yönergelerinin tümüyle ilgili olduğudur.

Yani - bulduğum şey bu.

Not : Bu, tam JQuery kitaplığının mevcut olmasını gerektirir ve yalnızca JQlite Angular'ın.error()

Bu Plunker'da iş başında görebilirsiniz.

Yönerge hemen hemen şuna benzer:

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

Bir hata oluştuğunda (bu, görüntünün mevcut olmaması veya erişilemez olması nedeniyle olabilir) yakalar ve tepki veririz. Görüntü boyutlarını da almayı deneyebilirsiniz - eğer ilk etapta görüntü / stil üzerinde mevcutlarsa. Değilse, kendinize bir varsayılan ayarlayın.

Bu örnek, bunun yerine bir resmin gösterilmesi için placehold.it kullanıyor.

Şimdi HER görüntü, kullanımdan bağımsız olarak srcveya ng-srchiçbir şey yüklenmemesi durumunda kendini kaplamış durumda ...


2
çok güzel çözüm! hadi bunu zirveye oylayalım!
Matthijs

1
Bu oldukça güzel söylemeliyim. Aslında çözülmezse hiçbir resmin gösterilmesini istemiyorum, bu yüzden kullandım: element.css ("display", "none"); tamamen gizlemek için
Pompey

1
güzel :) ya da element.remove () ile DOM'dan tamamen kaldırabilirsiniz; :)
Darren Wainwright

Harika çalışıyor, teşekkürler!
ecorvo

Çözümünüz biraz düzenlendi, böylece yol boş olduğunda da çalışır. stackoverflow.com/a/35884288/2014288
andrfas

21

Jason çözümünü her iki yükleme hatası durumunu veya boş bir kaynak dizesini yakalayacak şekilde genişletmek için bir saat ekleyebiliriz.

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
Güzel kod, ancak ng-ifşablonda (boş src dizesi)
neyle

Görünüşe göre ngSrc'yi kendi yönergenizle değiştirebilir ve ayrı bir errSrc yönergesine sahip olmak yerine errSrc'yi kullanmak için bağlama hatasını ayarlatabilirsiniz, eğer istediğiniz buysa. Kullanabilirsiniz attrs.$observe('ngSrc', function(value) {...});, ngSrc'nin $ watch yerine dahili olarak kullandığı şey bu
Jason Goemaat

Boşluklarla ilgili tüm sorun, değer boş ise ngSrc'nin src özniteliğini güncellememesidir, bu nedenle ngSrc'yi değiştiren kendi yönergeniz varsa, boş bir kontrole gerek kalmaz.
Jason Goemaat

1
@Pokono - hata fonksiyonunun içinde mevcut 'src' özniteliğinin 'errSrc' ile aynı olup olmadığını kontrol edebilirsiniz.
user2899845

1
@BiswasKhayargoli - abonelikten çıkmak için bir çağrı ekledi, böylece ilk yüklemeden sonra herhangi bir işlem maliyeti olmayacak
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'de:

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

JQuery kullanmadığı ve sorunu çözdüğü için bunun kabul edilen cevap olması gerektiğini düşünüyorum
Gregra

10

Resim 404 ise veya resim boşsa, direktiflere gerek yoksa bunun gibi ng-src filtresini kullanabilirsiniz :)

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

2
Hayır, eğer p.image bir AJAX çağrısında bir 404 döndürürse, bunu 'true' olarak değerlendirecek ve ikinci img / no-image.png'ye geçmeyecektir.
James Gentes

2
@JamesGentes - Durum böyle görünmüyor. Ng-src'nin bu kullanımı benim için tam olarak gösterildiği gibi çalışıyor. Ve çok daha basit.
shanemgrey

@shaneveeg teşekkürler, bu ilginç - Arka ucun neyin farklı olduğunu merak ediyorum. Node'u Express ile çalıştırıyorum, belki de farklı şekilde ele alıyor.
James Gentes

2
@JamesGentes - Önceki yorumumun düzeltmesi. OP, model tarafından döndürülen geçerli bir URI olduğunda, ancak takip edildiğinde bir 404 olduğunda bir çözüm arıyor. Bu durumda bu çözüm işe yaramaz, görüntü bozukluğuna neden olur. Açısal görüntü değeri için hiçbir şey döndürmezse, bu, yedeği doğru şekilde seçer.
shanemgrey

Laravel kullanıyorum ve 404, boş veya boş ise benim için mükemmel çalışıyor. ama belki Express 404 gibi kod yanıtı yerine bir tür hata döndürür, bu yüzden evet muhtemelen sunucu çerçevesine bağlıdır
NeoNe

8

Bunun gibi bir şey kullanıyorum, ancak team.logo'nun geçerli olduğunu varsayıyor. "Team.logo" ayarlanmamışsa veya boşsa varsayılanı zorlar.

<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" yu bir dize (doğru / yanlış) olarak değerlendirdiğinden bu doğrudur, oysa ng-src, 404 döndürse bile {{team.logo}} 'u doğru olarak görecek.
James Gentes


1

Yedek resmini kodunuzda bildirememenizin belirli bir nedeni var mı?

Anladığım kadarıyla, resim kaynağınız için iki olası durumunuz var:

  1. Bilgi parçalarını doğru şekilde ayarlayın <4 = Yedek görüntü.
  2. Bilgi parçalarını doğru şekilde ayarlayın == 4 = Oluşturulan URL.

Bunun uygulamanız tarafından ele alınması gerektiğini düşünüyorum - şu anda doğru URL belirlenemiyorsa bunun yerine bir yükleme / yedek / yer tutucu resim URL'si iletin.

Nedeni, herhangi bir zamanda görüntülenecek doğru URL'yi açıkça belirttiğiniz için hiçbir zaman 'eksik' bir resminiz olmamasıdır.


Maalesef, 4 değerin tümü ayarlanmış olsa bile, URL'nin hala 404 olabileceğini (kullanıcı yol boyunca klasörler ekleyebilir.) Bu arada, tüm değerler olduğunda URL'nin yanıt başlıklarını kontrol eden bir işlev ekledim. ayarlanır. Bunu özel bir muamele olmadan halletmek yine de güzel olurdu, bahse girerim
bununla

1
Harika, bunu bir cevap olarak göstermeli ve gelecekte arama yapan herkes için kabul edilmiş olarak işaretlemelisin.
Alex Osborn

1

Sorununuzu çözmek için http://angular-ui.github.io/ adresinde bulunan Angular UI Utils 'if ifadesi' direktifini kullanmak isteyebileceğinizi öneririm . Ben de tam olarak aynı şeyi yapmak için kullandım.

Bu test edilmemiştir, ancak aşağıdaki gibi bir şey yapabilirsiniz:

Denetleyici kodu:

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

(veya daha basit)

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

Görünümde HTML: <img ui-if="showImage()" ng-src="images/{{data.value}}.jpg" />

Daha da basit bir ifadeyle, bir kapsam özelliği kullanabilirsiniz:

Denetleyici kodu:

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

Görünümde HTML: <img ui-if="showImage" ng-src="images/{{data.value}}.jpg" />

Bir yer tutucu görüntüsü için, başka bir benzer <img>etiket ekleyin, ancak ui-ifparametrenizin başına bir ünlem işareti ( !) ekleyin ve ngSrc'nin yer tutucu görüntünün yolunu olmasını sağlayın veya srcnormal HTML'ye göre bir etiket kullanın .

Örneğin. <img ui-if="!showImage" src="images/placeholder.jpg" />

Açıkçası, yukarıdaki kod örneklerinin tümü, değer1, değer2, değer3 ve değer4'ün her birinin, 4 bilginizin her biri eksik olduğunda null/ falseolduğunda (ve dolayısıyla, tamamlandıklarının boole değerine) eşit olacağını varsaymaktadır true.

PS. AngularUI projesi yakın zamanda alt projelere bölündü ve dokümantasyonu ui-ifşu anda eksik görünüyor (muhtemelen pakette bir yerde olsa da). Bununla birlikte, görebileceğiniz gibi kullanımı oldukça basittir ve bunu takıma da belirtmek için Angular UI projesine bir Github 'sorunu' kaydettim.

GÜNCELLEME: AngularUI projesinde 'ui-if' eksiktir çünkü temel AngularJS koduna entegre edilmiştir! Yalnızca v1.1.x itibarıyla, şu anda "kararsız" olarak işaretlenmiştir.


ng-ifçekirdek btw haline getirildi (yanılmıyorsam 1.1.5 itibariyle).
holographic-

1

İşte yerel javascript kullanarak bulduğum bir çözüm. Görüntünün bozuk olup olmadığını kontrol ediyorum, ardından her ihtimale karşı görüntüye bir sınıf ekliyorum ve kaynağı değiştiriyorum.

Cevabımın bir kısmını bir Quora cevabından aldım 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

Kendi çözümümle geldim. Hem src hem de ngSrc boşsa ve img 404 döndürürse görüntünün yerini alır.

(@Darren çözümünün çatalı)

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

Bu, ng-src'nin var olup olmadığını kontrol etmek için yalnızca iki kez döngüye izin verecektir, aksi takdirde err-src'yi kullanın, bu döngü devam etmesini engeller.

(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);
                }              
            });
            }
        }
    }
})();
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.