First, are you familiar with ng-src? It's used for interpolated src expressions to avoid the browser trying to fetch from "path/to/{{url}}" instead of the actual url (e.g. "/path/to/image1.png"). It also doesn't load the image if url is undefined.
Second, the $compile(element)(scope) is completely unnecessary (and in fact, incorrect) - if nothing else, you are needlessly recompiling the defaultImage directive.
EDIT:
Huh... this is a case of "overthinking" on my part... By far, the easiest way to achieve a default URL is like so (no directives required):
<img ng-src="{{entity.image || '/default/url'}}">
Or, if you have a scope variable $scope.defaultUrl, then:
<img ng-src="{{entity.image || defaultUrl}}">
ORIGINAL ANSWER:
So, let's see how ngSrc handles the "good" case and create something similar for the default case. Here's a simplified snippet of code from the ngSrc source code:
link: function(scope, element, attr){
attr.$observe("ngSrc", function(value) {
if (!value) {
return;
}
attr.$set("src", value);
// on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
// then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
// to set the property as well to achieve the desired effect.
// we use attr[attrName] value since $set can sanitize the url.
if (msie) element.prop("src", attr["src"]);
});
}
So, using a similar approach:
.directive("defaultImage", function(){
return {
link: function(scope, element, attr){
// what Angular uses
// https://github.com/angular/angular.js/blob/v1.4.5/src/Angular.js#L191
var msie = document.documentMode;
var defaultImageUrl = "/path/to/default.png";
attr.$observe("ngSrc", function(value){
if (!value){
attr.$set("src", defaultImageUrl);
if (msie) element.prop("src", attr["src"]);
}
})
}
}
})
Demo