nếu đường dẫn ngSrc chuyển thành 404, có cách nào để chuyển về mặc định không?


129

Ứng dụng tôi đang xây dựng yêu cầu người dùng của tôi thiết lập 4 mẩu thông tin trước khi hình ảnh này thậm chí có cơ hội tải. Hình ảnh này là phần trung tâm của ứng dụng, vì vậy liên kết hình ảnh bị hỏng làm cho nó trông giống như toàn bộ sự việc. Tôi muốn có một hình ảnh khác diễn ra trên 404.

Có ý kiến ​​gì không? Tôi muốn tránh viết một chỉ thị tùy chỉnh cho việc này.

Tôi đã ngạc nhiên rằng tôi không thể tìm thấy một câu hỏi tương tự, đặc biệt là khi câu hỏi đầu tiên trong các tài liệu là cùng một câu hỏi!

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


Điều này có thể có liên quan: stackoverflow.com/q/13781685/1218080
nguyên tắc ba chiều

Câu trả lời:


252

Đây là một chỉ thị khá đơn giản để theo dõi lỗi khi tải hình ảnh và thay thế 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);
        }
      });
    }
  }
});

Nếu bạn muốn hiển thị hình ảnh lỗi khi ngSrc trống, bạn có thể thêm phần này (Plunker) :

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

Vấn đề là ngSrc không cập nhật thuộc tính src nếu giá trị trống.


Hoạt động tốt nếu url bị hỏng (404), nhưng nếu đó là một chuỗi trống ng-src thì âm thầm nuốt lỗi.
Stephen Patten

2
Nếu một chuỗi rỗng không hợp lệ cho mô hình của bạn, thì hãy làm cho nó để biểu thức bạn liên kết với ng-src không trả về một chuỗi trống.
Justin Lovero

Tập lệnh được cập nhật để hỗ trợ sử dụng srcthuộc tính cho err-srchình ảnh: plnkr.co/edit/b05WtghBOHkxKdttZ8q5
Ryan Schumacher

@JustinLovero Tôi coi đó là một lỗi trong góc và báo cáo nó. Vấn đề là ngSrc sẽ không đặt thuộc tính src nếu giá trị trống. Đó thực sự có thể là một vấn đề nếu ví dụ bạn đang hiển thị một điện thoại và tải một điện thoại khác với ajax bị thiếu url hình ảnh. Hình ảnh điện thoại cũ sẽ tiếp tục được hiển thị, nhưng tôi nghĩ rằng một lỗi hoặc giữ chỗ sẽ phù hợp hơn. Vâng, bạn có thể xử lý nó trong mô hình của mình, nhưng hành vi để lại một hình ảnh cũ là, tôi nghĩ, sai hơn là hiển thị một lỗi.
Jason Goemaat

@JasonGoemaat, tôi sẽ làm thế nào để thay thế hình ảnh bị hỏng bằng văn bản?
simeg

48

Ít đến bữa tiệc, mặc dù tôi đã đưa ra một giải pháp cho ít nhiều vấn đề tương tự trong một hệ thống tôi đang xây dựng.

Tuy nhiên, ý tưởng của tôi là xử lý MỌI imgthẻ hình ảnh trên toàn cầu.

Tôi không muốn phải tiêu hóa HTMLnhững chỉ thị không cần thiết, chẳng hạn như err-srcnhững chỉ thị được trình bày ở đây. Rất thường xuyên, đặc biệt là với các hình ảnh động, bạn sẽ không biết nếu nó bị mất cho đến khi quá muộn. Thêm các chỉ thị bổ sung vào cơ hội không có hình ảnh có vẻ quá mức đối với tôi.

Thay vào đó, tôi mở rộng imgthẻ hiện có - thực sự là những gì mà các chỉ thị của Angular hướng tới.

Vì vậy - đây là những gì tôi nghĩ ra.

Lưu ý : Điều này đòi hỏi phải có thư viện JQuery đầy đủ và không chỉ các tàu Angular JQlite vì chúng tôi đang sử dụng.error()

Bạn có thể thấy nó hoạt động tại Plunker này

Lệnh này trông khá giống như thế này:

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

Khi xảy ra lỗi (nguyên nhân là do hình ảnh không tồn tại hoặc không thể truy cập được, v.v.), chúng tôi chụp và phản ứng. Bạn cũng có thể cố gắng để có được kích thước hình ảnh - nếu chúng có mặt trên hình ảnh / kiểu ở vị trí đầu tiên. Nếu không, sau đó đặt cho mình một mặc định.

Ví dụ này đang sử dụng placekeep.it cho một hình ảnh để hiển thị thay thế.

Bây giờ MỌI hình ảnh, bất kể sử dụng srchay ng-srctự bao phủ trong trường hợp không có gì tải lên ...


2
giải pháp rất hay! Hãy bình chọn cái này lên đầu!
Matthijs

1
Điều này khá đẹp tôi phải nói. Tôi thực sự không muốn bất kỳ hình ảnh nào hiển thị nếu nó không giải quyết được vì vậy tôi đã sử dụng: Element.css ("display", "none"); chỉ cần che giấu nó hoàn toàn
Pompey

1
tốt đẹp :) hoặc bạn có thể chỉ cần xóa nó khỏi DOM hoàn toàn, với Element.remove (); :)
Darren Wainwright

Hoạt động tuyệt vời, Cảm ơn!
ecorvo

Chỉnh sửa một chút giải pháp của bạn, vì vậy nó cũng hoạt động khi đường dẫn trống. stackoverflow.com/a/35884288/2014288
andrfas

21

Để mở rộng giải pháp Jason để bắt cả hai trường hợp lỗi tải hoặc chuỗi nguồn trống, chúng ta chỉ cần thêm đồng hồ.

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
Mã đẹp, nhưng dường như quá mức cần thiết để thêm đồng hồ cho những gì có thể dễ dàng kiểm tra ng-iftrong mẫu (chuỗi src trống)
alonisser 18/12/13

Có vẻ như bạn chỉ có thể thay thế ngSrc bằng chỉ thị của riêng mình và yêu cầu nó thiết lập liên kết bị lỗi để sử dụng errSrc thay vì có một lệnh errSrc riêng nếu đó là điều bạn muốn. Bạn có thể sử dụng attrs.$observe('ngSrc', function(value) {...});, đó là những gì ngSrc sử dụng nội bộ thay vì $ watch
Jason Goemaat

Toàn bộ vấn đề với khoảng trống là do ngSrc không cập nhật thuộc tính src nếu giá trị trống, vì vậy nếu bạn có lệnh riêng của mình thay thế ngSrc thì sẽ không cần kiểm tra trống.
Jason Goemaat

1
@Pokono - bạn có thể kiểm tra bên trong hàm lỗi xem thuộc tính 'src' hiện tại có giống với 'errSrc' hay không.
dùng2899845

1
@BiswasKhayargoli - đã thêm một cuộc gọi để hủy đăng ký, do đó, nó sẽ không có bất kỳ chi phí xử lý nào sau khi tải ban đầu
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;
            });
        }
    };
});

trong HTML:

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

Tôi cảm thấy đây phải là câu trả lời được chấp nhận vì nó không sử dụng jQuery và giải quyết vấn đề
Gregra

10

Nếu hình ảnh là 404 hoặc hình ảnh trống rỗng, bất cứ điều gì không cần chỉ thị, bạn chỉ cần sử dụng bộ lọc ng-src như thế này :)

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

2
Không, nếu p.image trả về 404 trong cuộc gọi AJAX, nó sẽ coi đó là 'true' và không chuyển sang img / no-image.png thứ hai.
James Gentes

2
@JamesGentes - Điều đó dường như không phải là trường hợp. Việc sử dụng ng-src này hoạt động với tôi chính xác như được hiển thị. Và nó đơn giản hơn nhiều.
shanemgrey

@shaneveeg cảm ơn, điều đó thật thú vị - Tôi tự hỏi liệu mặt sau có gì khác biệt không. Tôi đang chạy Node với Express, có lẽ nó xử lý nó khác đi.
James Gentes

2
@JamesGentes - Sửa bình luận trước đây của tôi. OP đang tìm kiếm một giải pháp khi có một URI hợp lệ được mô hình trả về, nhưng 404 khi nó đi theo. Trong trường hợp đó, giải pháp này không hoạt động, nó dẫn đến hình ảnh bị hỏng. Nếu góc không trả về giá trị hình ảnh, điều này sẽ chọn chính xác dự phòng.
shanemgrey

Tôi đang sử dụng Laravel và nó hoạt động hoàn hảo đối với tôi nếu 404, null hoặc trống là trường hợp. nhưng có lẽ Express trả về một số loại lỗi thay vì phản hồi mã như 404 nên có thể phụ thuộc vào khung máy chủ
NeoNe

8

Tôi sử dụng một cái gì đó như thế này, nhưng nó giả sử rằng team.logo là hợp lệ. Nó buộc mặc định nếu "team.logo" không được đặt hoặc trống.

<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
Điều này đúng, vì nó đánh giá "team.logo" là một chuỗi (đúng / sai) trong khi ng-src sẽ thấy {{team.logo}} là đúng ngay cả khi nó trả về 404.
James Gentes

2

Bạn không cần góc cạnh cho điều đó, hoặc thậm chí CSS hoặc JS. Nếu bạn muốn, bạn có thể gói câu trả lời này (được liên kết) trong một chỉ thị đơn giản để làm cho nó đơn giản hơn, thích hoặc một cái gì đó, nhưng đó là một quy trình khá đơn giản ... chỉ cần bọc nó trong thẻ đối tượng ...

Cách ẩn Biểu tượng bị hỏng Biểu tượng chỉ sử dụng CSS / HTML (không có js)


1

Có một lý do cụ thể nào bạn không thể khai báo hình ảnh dự phòng trong mã của mình không?

Theo tôi hiểu, bạn có hai trường hợp có thể cho nguồn hình ảnh của mình:

  1. Đặt chính xác các mẩu thông tin <4 = Hình ảnh dự phòng.
  2. Đặt chính xác các mẩu thông tin == 4 = URL được tạo.

Tôi nghĩ rằng ứng dụng này nên được xử lý bởi ứng dụng của bạn - nếu hiện tại URL chính xác không thể được xác định, thay vào đó hãy chuyển URL hình ảnh tải / dự phòng / giữ chỗ.

Lý do là bạn không bao giờ có hình ảnh 'mất tích', vì bạn đã tuyên bố rõ ràng URL chính xác để hiển thị tại bất kỳ thời điểm nào.


Xin lỗi, tôi nên làm rõ rằng ngay cả khi cả 4 giá trị được đặt, URL vẫn có thể 404 (người dùng có thể thêm thư mục trên đường đi.) Trong khi đó, tôi đã thêm một chức năng kiểm tra các tiêu đề phản hồi của URL khi tất cả các giá trị được thiết lập. Sẽ vẫn tốt nếu xử lý việc này mà không cần đối xử đặc biệt, tôi cá là tôi sẽ gặp lại chuyện này :)
will_hardin

1
Thật tuyệt, bạn nên thể hiện điều đó như một câu trả lời và đánh dấu nó là chấp nhận cho bất kỳ ai tìm kiếm trong tương lai.
Alex Osborn

1

Tôi đề nghị rằng bạn có thể muốn sử dụng lệnh Angular UI Utils 'if statement' để giải quyết vấn đề của mình, như được tìm thấy tại http://angular-ui.github.io/ . Tôi vừa sử dụng nó để làm chính xác điều tương tự.

Điều này chưa được kiểm tra, nhưng bạn có thể làm một cái gì đó như:

Mã điều khiển:

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

(hoặc đơn giản hơn)

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

HTML trong Chế độ xem: <img ui-if="showImage()" ng-src="images/{{data.value}}.jpg" />

Hoặc thậm chí đơn giản hơn, bạn chỉ có thể sử dụng một thuộc tính phạm vi:

Mã điều khiển:

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

HTML trong Chế độ xem: <img ui-if="showImage" ng-src="images/{{data.value}}.jpg" />

Đối với hình ảnh giữ chỗ, chỉ cần thêm một <img>thẻ tương tự khác nhưng thêm vào ui-iftham số của bạn bằng dấu chấm than ( !) và làm cho ngSrc có đường dẫn đến hình ảnh giữ chỗ hoặc chỉ sử dụng srcthẻ theo HTML thông thường.

ví dụ. <img ui-if="!showImage" src="images/placeholder.jpg" />

Rõ ràng, tất cả các mẫu mã ở trên đều giả định rằng mỗi giá trị1, value2, value3 và value4 sẽ tương đương với null/ falsekhi mỗi 4 thông tin của bạn không đầy đủ (và do đó cũng có giá trị boolean truekhi chúng hoàn thành).

Tái bút Dự án AngularUI gần đây đã được chia thành các tiểu dự án và tài liệu ui-ifdường như hiện đang bị thiếu (có lẽ nó nằm trong gói ở đâu đó). Tuy nhiên, nó khá đơn giản để sử dụng như bạn có thể thấy và tôi đã ghi lại một 'vấn đề' của Github trên dự án Angular UI để chỉ ra cho nhóm.

CẬP NHẬT: 'ui-if' bị thiếu trong dự án AngularUI vì nó được tích hợp vào mã AngularJS cốt lõi! Tuy nhiên, chỉ kể từ v1.1.x, hiện được đánh dấu là 'không ổn định'.


ng-ifbiến nó thành lõi btw (kể từ 1.1.5 nếu tôi không nhầm).
nguyên tắc ba chiều

1

Đây là một giải pháp tôi đã đưa ra bằng cách sử dụng javascript gốc. Tôi đang kiểm tra xem hình ảnh có bị hỏng hay không, sau đó thêm một lớp vào hình ảnh và thay đổi nguồn.

Tôi đã nhận được một phần câu trả lời của mình từ câu trả lời của 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

Đến với giải pháp của riêng tôi. Nó thay thế hình ảnh cả nếu src hoặc ngSrc trống và nếu img trả về 404.

(ngã ba của giải pháp @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

Điều này sẽ chỉ cho phép lặp hai lần, để kiểm tra xem ng-src không tồn tại khác có sử dụng err-src hay không, điều này ngăn chặn việc tiếp tục lặp.

(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);
                }              
            });
            }
        }
    }
})();
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.