web-dev-qa-db-fra.com

si un chemin ngSrc se résout en 404, existe-t-il un moyen de revenir à une valeur par défaut?

L'application que je construis nécessite que mon utilisateur définisse 4 informations avant que cette image ait même une chance de chargement. Cette image est la pièce maîtresse de l'application, le lien de l'image brisée donne l'impression que tout est bouché. J'aimerais qu'une autre image prenne sa place sur un 404.

Des idées? Je voudrais éviter d'écrire une directive personnalisée pour cela.

J'ai été surpris de ne pouvoir trouver une question similaire, surtout lorsque la première question de la documentation est la même!

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

129
will_hardin

C'est une directive assez simple de rechercher une erreur lors du chargement d'une image et de remplacer le code 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);
        }
      });
    }
  }
});

Si vous souhaitez afficher l'image d'erreur lorsque ngSrc est vide, vous pouvez ajouter ceci (Plunker) :

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

Le problème est que ngSrc ne met pas à jour l'attribut src si la valeur est vide.

251
Jason Goemaat

Un peu tard dans la soirée, même si j’ai trouvé une solution à peu près au même problème dans un système que je construis. 

Cependant, mon idée était de gérer globalement CHAQUE balise img de chaque image.

Je ne voulais pas avoir à pomper ma HTML avec des directives inutiles, telles que celles de err-src présentées ici. Assez souvent, surtout avec des images dynamiques, vous ne saurez pas s'il le manque avant qu'il ne soit trop tard. Ajouter des directives supplémentaires au hasard d'une image manque me semble exagéré.

Au lieu de cela, j'étends la balise img existante - ce qui est en réalité ce que sont les directives angulaires. 

Alors, voici ce que je suis venu avec. 

Note: Cela nécessite la présence de la bibliothèque complète JQuery et pas uniquement de la version JQlite Angular, car nous utilisons .error()

Vous pouvez le voir en action à cet endroit Plunker

La directive ressemble beaucoup à ceci:

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

Lorsqu'une erreur se produit (ce sera parce que l'image n'existe pas ou est inaccessible, etc.), nous capturons et réagissons. Vous pouvez aussi essayer d’obtenir les tailles d’image - s’ils étaient présents dans l’image/le style en premier lieu. Sinon, définissez-vous par défaut.

Cet exemple utilise placehold.it pour une image à afficher à la place.

Maintenant, CHAQUE image, indépendamment de l'utilisation de src ou ng-src, est recouverte au cas où rien ne se charge ...

48
Darren

Pour étendre la solution de Jason afin d’attraper les deux cas d’erreur de chargement ou une chaîne source vide, nous pouvons simplement ajouter une surveillance.

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

    }
  }
});
21
user2899845
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;
            });
        }
    };
});

en HTML: 

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

Si image est 404 ou image vide, quelle que soit la méthode utilisée, vous pouvez simplement utiliser le filtre ng-src comme ceci :)

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

J'utilise quelque chose comme ça, mais cela suppose que team.logo est valide. Il force les valeurs par défaut si "team.logo" n'est pas défini ou est vide. 

<img ng-if="team.logo" ng-src="https://api.example.com/images/{{team.logo}}">
<img ng-hide="team.logo" ng-src="img/default.png">
8
evandentremont

Vous n'avez pas besoin d'angular pour cela, ni même de CSS ou de JS. Si vous le souhaitez, vous pouvez envelopper cette réponse (liée) dans une directive simple pour la simplifier, par exemple, mais c'est un processus assez simple ... il suffit de l'envelopper dans une balise object ...

Comment cacher une image brisée Icône en utilisant seulement CSS/HTML (sans js)

2
Nick Steele

Voici une solution que j'ai proposée avec l'utilisation de javascript natif. Je vérifie si l'image est cassée, puis en ajoutant une classe à l'image au cas où et en changeant la source.

J'ai obtenu une partie de ma réponse d'une réponse 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';
            };
        }
    }
});
1
Anselm Marie

Existe-t-il une raison spécifique pour laquelle vous ne pouvez pas déclarer l'image de secours dans votre code?

Si je comprends bien, vous avez deux cas possibles pour votre source d’image:

  1. Définissez correctement les éléments d’information <4 = image de secours.
  2. Définir correctement les éléments d’information == 4 = URL générée.

Je pense que cela devrait être géré par votre application. Si l'URL correcte ne peut pas être déterminée pour le moment, transmettez plutôt une URL d'image de chargement/de secours/d'espace réservé.

Le raisonnement est que vous n'avez jamais d'image "manquante", car vous avez explicitement déclaré l'URL correcte à afficher à tout moment.

1
Alex Osborn

Je suggère que vous souhaitiez utiliser la directive 'if statement' de l'utilitaire Angular UI Utils pour résoudre votre problème, disponible sur http://angular-ui.github.io/ . Je viens de l'utiliser pour faire exactement la même chose.

Ceci n’a pas été testé, mais vous pourriez faire quelque chose comme:

Code du contrôleur:

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

(ou plus simple)

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

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

Ou encore plus simplement, vous pouvez simplement utiliser une propriété de portée:

Code du contrôleur:

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

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

Pour une image d'espace réservé, ajoutez simplement une autre balise <img> similaire mais ajoutez à votre paramètre ui-if un point d'exclamation (!) et faites en sorte que ngSrc ait le chemin d'accès à l'image d'espace réservé ou utilisez simplement une balise src selon le code HTML normal.

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

Évidemment, tous les exemples de code ci-dessus supposent que valeur1, valeur2, valeur3 et valeur4 équivaudront à null/false lorsque chacune de vos 4 informations est incomplète (et donc également à une valeur booléenne de true quand elles sont complètes ).

PS. Le projet AngularUI a récemment été divisé en sous-projets et la documentation pour ui-if semble faire actuellement défaut (elle est probablement quelque part dans le package). Cependant, il est assez simple à utiliser, comme vous pouvez le constater, et j’ai consigné un «problème» de Github dans le projet d’interface utilisateur angulaire pour le signaler également à l’équipe. 

MISE À JOUR: 'ui-if' manque dans le projet AngularUI car il a été intégré au code AngularJS! Seulement à partir de la version 1.1.x cependant, qui est actuellement marqué comme "instable".

1
Matty J

Entré avec ma propre solution . Il remplace image à la fois si src ou ngSrc est vide et si img renvoie 404.

(fork de la solution @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
andrfas

Cela permettra seulement de boucler deux fois, pour vérifier si le ng-src n'existe pas, sinon utilisez err-src, ceci empêchera la boucle continue.

(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);
                }              
            });
            }
        }
    }
})();
0