15

I've created an AngularJS application that loads images from an OAuth secured backend. My OAuth library is configured by adding an extra interceptor to the Angular $httpProvider to add the correct authentication header.

My source code in my HTML template looks like this:

<img ng-src="{{ '/users/1/images/' + imageId }}">

My problem is that the http request that is created by the ngSrc directive is ignored by the $http implementation, which results in a request with the wrong authentication. The normal API calls function correct (the ones invoked by my controllers/services by using $http and $resource directly).

4 Answers 4

25

Based on Michal's answer the directive could look like the below

app.directive('httpSrc', [
        '$http', function ($http) {
            var directive = {
                link: link,
                restrict: 'A'
            };
            return directive;

            function link(scope, element, attrs) {
                var requestConfig = {
                    method: 'Get',
                    url: attrs.httpSrc,
                    responseType: 'arraybuffer',
                    cache: 'true'
                };

                $http(requestConfig)
                    .then(function(response) {
                        var arr = new Uint8Array(response.data);

                        var raw = '';
                        var i, j, subArray, chunk = 5000;
                        for (i = 0, j = arr.length; i < j; i += chunk) {
                            subArray = arr.subarray(i, i + chunk);
                            raw += String.fromCharCode.apply(null, subArray);
                        }

                        var b64 = btoa(raw);

                        attrs.$set('src', "data:image/jpeg;base64," + b64);
                    });
            }

        }
    ]);

You would then use it as follows

<img http-src="www.test.com/something.jpeg">
Sign up to request clarification or add additional context in comments.

6 Comments

Hi there, I am using this directive - the problem seems to be that http-src as defined is not being recomputed at each iteration, so if I point it to an image that keeps changing, it does not update. Any thoughts?
@user1361529 Watch the attribute for changes and then re execute the request. jsfiddle.net/83aaecyy
works with dynamic url too: <img http-src="{{user.photo.url}}"/>
u save my life today
What's the point of iterating the response data in smaller chunks? I understand that if the buffer would not yet be read fully then it would be beneficial to gradually read from the pipe to not fill the memory but in this case I think the string is already fully in memory and splitting and going it though in slices only takes more memory.
|
11

The ngSrc directive just controls the usual src attribute for an img, which makes the browser request the image just like any other image, not via Javascript, so I don't think this can be intercepted.

However, what you could do, is write a new directive, save httpSrc. This then can fetch the image using a call to $http, and then create a data URI with the response using something like Using raw image data from ajax request for data URI (although I'm not sure of the browser support for it).

1 Comment

Thanks. I was already considering this, but I worried about the performance impact on the DOM when I add multiple chunks of Base64 to it. I hoped there would be a clean and elegant solution.
5

As said here you can use angular-img-http-src (bower install --save angular-img-http-src if you use Bower).

If you look at the code, it uses URL.createObjectURL and URL.revokeObjectURL which are still draft on 19 April 2016. So look if your browser supports it.

In order to use it, declare 'angular.img' as a dependency to your app module (angular.module('myapp', [..., 'angular.img'])), and then in your HTML you can use http-src attribute for <img> tag.

In your example, you can write: <img http-src="/users/1/images/{{imageId}}">

1 Comment

I think using an object URL is better than my original answer of using a data URI, assuming the browser support is acceptable.
0

This is a little old, but thought I would add another method for finding an image w/o using an interceptor. In my case, I needed to find the image path from the rails assets pipeline.

There was a blog from Codetunes (http://codetunes.com/2014/5-tips-on-how-to-use-angularjs-with-rails-that-changed-how-we-work/) that described how they find templates. This makes use of an interceptor but doesn't work for images.

The solution I used requires you to use a model for the ng-src value. Within the model, I call a helper method from a service that utilizes the Rails.templates variable setup from the above blog article.

So, it looks like the following:

angular.module('myApp').factory('RailsAssetService', function(Rails) {

    function RailsAssetService() {

    }

    RailsAssetService.getAssetsUrl = function(url) {
        var railsUrl = Rails.templates[url];
        if (railsUrl === undefined)
            railsUrl = url;
        return railsUrl;
    }

    return RailsAssetService;
});

and in the controller:

vm.creditCardsImage = RailsAssetService.getAssetsUrl('credit-cards-logo.gif');

and in the view:

<img ng-src="{{vm.creditCardsImage}}">

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.