Slimmage and Angular.js working together

When creating responsive websites you will likely end up using a library such as Slimmage or Picturefill to tailor images for the users screen dimensions.

The same image served by the application needs to be of high enough resolution to look good on larger monitors, but should also load quickly on mobile devices with considerably smaller screen dimensions. Libraries like Slimmage and Picturefill work by replacing your image tags with some alternative markup, this is then used as a place-holder that script will put the final image into. These will often work in conjunction with a server side re-size library such as ImageResizer.Net. For example when using Slimmage you can replace your image tags with a no-script element like so:

<noscript data-slimmage>
    <img class="halfsize" src="http://z.zr.io/ri/1s.jpg?width=150" />
<noscript>

Slimmage will then inspect the page and replace the no-script tags that have the data-slimmage attribute with the appropriate sized image element. The beauty of this setup is that when JavaScript is not present the images still load without the risk of a double request.

Occasionally you will encounter a scenario where you want to dynamically add or modify an image with script after the page has loaded. The issue arises because by the time the image place-holder has loaded Slimmage has already inspected the page elements for image replacements and re-sizing.

With AngularJs you may be doing something along the following lines. Alternatively you may want load an image in response to user actions after page load.

<img alt="{{ item.AltText }}" data-slimmage data-src="{{ item.Url }}" />

Luckily Slimmage exposes a method to force it to reinspect the page elements for re-sizing. A custom angular directive can then be added and called by angular when binding models rather than the normal page load and Slimmage events.

The only drawback to this solution is that Slimmage cannot be minimized otherwise the directive call will fail.

amlApp.directive('slimmage', ['$window', function ($window) {
    return {
        link: function (scope, element, attrs) {
            var url = attrs.src; 
            if (attrs.slimmage) {
                $window.slimmage.adjustImageSrc(element.context, url);
            } else {
                element.attr('src', url);
            }
        }
    };
}]);

The new directive can then be added allowing Slimmage to be called after the model has been bound.

<img alt="{{ item.AltText }}" data-slimmage="true" data-src="{{ item.Url }}" />