In order to show a default image (instead of a broken image) when the image is not physically present, I use this piece of code:
<img ng-show="order.img" ng-src="{{order.img | fPath}}" onerror="this.style.display='none';"/>
<img ng-hide="order.img" ng-src="{{'default.png' | imgPath}}" />
Here fPath
,imgPath
are filters that append a prefix to the image name.
Most of the times it works well (the image gets rendered). However, in some cases the image does not show up. In such cases, the angular snippet gets translated to this html (note the style="display: none;"
in the first img tag):
<img ng-show="order.img" ng-src="http://xx.s3.amazonaws.com/o/img1.jpg" onerror="this.style.display='none'" src="http://xx.s3.amazonaws.com/o/img1.jpg" style="display: none;">
<img ng-hide="order.img" ng-src="http://xx.s3.amazonaws.com/default.png" class="ng-hide" src="http://xx.s3.amazonaws.com/default.png" style="">
Question: What could be the reason for this? And possible workarounds? Is it that the onerror
gets triggered sooner than expected?
PS: http://xx.s3.amazonaws.com/o/img1.jpg
is a valid image path and is available.
Update: This is how the app/route/controller is defined
Route
t_app.config(function ($stateProvider, $urlRouterProvider, $httpProvider) {
// ...
$stateProvider.state('ref', {
url: '/orders/:ref',
templateUrl: 'views/order.htm',
controller: 'orderController'
});
// ...
});
Controller
t_app.controller('orderController', ['$scope', '$stateParams', function($scope, $stateParams) {
// Load the order (this step takes a while)
}]);
I think what is happening to you is this: http://plnkr.co/edit/8JL0Op?p=preview
angular.module('app.helper', [])
.controller('ImgController', ['$scope', '$timeout', function($scope, $timeout) {
$scope.img = "";
$timeout(function(){
$scope.img = "9c5595db-db21-4783-902a-8e80b84ae22c/6b89ed2b-878a-4f76-95c4-76ee95f47d9a.jpg";
}, 1500);
}]);
filter.$inject = ["$filter"];
angular.module('app.helper').filter('addPath', filter);
function filter($filter) {
function filterFn(input) {
return "http://cdn.playbuzz.com/cdn/"+input;
}
return filterFn;
}
The filter adds the prefix before order.img
is set, so the img src will be (until order is lodaded) the prefix only, without the image name, resulting in a wrong src.
I think, but i can't be 100% sure, the reason because it happens only sometimes is that sometime $scope.order
is loaded before (maybe when the results are cached or something) onerror triggers and some times after.
It's hard to determine the execution order when you mix native javascript and angular
You can probably avoid this by adding a check in your filter: if the value passed to the filter is null, undefined or an empty string then return null in that case. Something like this
return typeof input === "undefined" || input === null || input === "" ? null : "http://cdn.playbuzz.com/cdn/"+input;