Using CDN with <img> tags

1.2k Views Asked by At

I have just added a CDN service to make my website load faster. I have a question regarding photos that are fetched using a <img> tag.

I have many cases like this:

// userProfile.thumbnailPhotoSrc = some/relative/path.png    
ng-src="{{userProfile.thumbnailPhotoSrc}}"

(I use AngularJS).

On startup, I have a script that saves the CDN endpoint to window.cdn variable. In case the script decides there's no endpoint available:

window.cdn = '';

So I want to be able to do something like:

ng-src="window.cdn + {{userProfile.thumbnailPhotoSrc}"

But this is impossible, as window.cdn is not evaluated. But neither this is working:

ng-src="{{window.cdn + userProfile.thumbnailPhotoSrc}"

Because I can only access $scope properties under {{}}. I can't save the CDN endpoint to $scope, because there exists a $scope for every controller (I have many, this is not maintainable).

The last thing I thought of, hoping ng-src allows that - is adding a transformation function that is run on any ng-src attribute, but I could not find how to do that.

What do you suggest I do? keep in mind that I would like the website fetch the photo from the CDN and fallback to the origin server (fetch the relative path) in case of CDN malfunction. How can I obtain that behavior?

Thanks

2

There are 2 best solutions below

2
vvondra On

You could create a custom filter in Angular

You would then have then in your templates:

ng-src="{{userProfile.thumbnailPhotoSrc | cdn}"

You could add the $window service as a dependency to the filter service so you don't have to pull it from the global object and you can test the filter as well.

5
Hoyen On

If you are trying to update all the <img> tag's src. You can create a directive:

angular.module('imageCdnSrc', [])
.directive('img',['$interpolate', function($interpolate) {
    return {
    restrict: 'E',
    scope: false,
    compile: function(element, attrs) {
      var ngSrc = attrs.ngSrc;
      delete attrs.ngSrc; // prevent ngSrc directive to trigger

      return function($scope,element,attrs) {
        var ngSrcVal = $interpolate(ngSrc)($scope); //returns the string value of ngSrc

        /* Add Logic Below to decide what to do */
        if(window.cdn && ngSrcVal && ngSrcVal.length>0){
          attrs.ngSrc = window.cdn + ngSrcVal;
          /* if image fails to load with cdn, load the default */
          element.one('error', function() {
            angular.element(this).attr("src", ngSrcVal);
          });
        }
        else{
          attrs.ngSrc = ngSrcVal;
        }
      };      
    }
  };
}]);