Handling image load errors in Ext JS universal apps

— 5 minute read


When displaying images in our web applications we never want to see a dead image shown when an image file has been moved or deleted. This can become a more prevalent problem when we are using dynamic image URLs or convention based URL structure. For example, we might always load a User's profile image by combining their ID number and Last name to form the filename and always looking in a specific assets folder - resources/profiles/12345_ashworth.jpg.

The way to avoid having these dead image placeholders is to have a standard fallback image that we can use in place of the missing picture - often this is a grey silhouette of a head. This is all well and good but we generally don't know that an image is missing until it's too late - when the request for the image returns a 404.

We solve this problem by using the error event of the Ext.dom.Element class to recognise the failure to load the image. This event encapsulates the error process of the underlying <img> element - onerror. When this event fires we can then replace the src attribute with the fallback placeholder image. This seems like a pretty simple solution (and it is!) but it's very effective in keeping our app's images nice and tidy.

We're going to demonstrate how to implement this by creating an extension of the Ext.Img class which is present in both the Classic and Modern toolkits, so makes this a great Universal solution, albeit with a few toolkit specific tweaks!

The Solution

So, as I've said we're going to make a new component that extends the Ext.Img class. Let's kick off and lay down the initial class code. You can explore the working code in the following Sencha Fiddle

We'll also make a quick test case to show the component in action - nothing fancy here, just rendering an image to the <body> with a dud src config.

As we expect this will result in a broken image placeholder being shown:

image

Reacting to a Broken Image

As we said earlier we need to use the error event of the Ext.dom.Element class to determine if the image failed to load.

Classic

The Ext.Img class caches a reference to the rendered <img> element in the imgEl property in the Classic toolkit which we can tap into from the onRender method. We will override this method and add a listener to the event.

With this code in place we can rerun it and see the console log output in the Developer Tools.

image

Modern

The Modern toolkit uses a slightly different approach so we must adapt our solution slightly. The Ext.Img class in Modern can use both a real <img> element or a background image - this is determined by the mode config. This means we must cater for both scenarios. The other different is that it already taps into the error event so we must override it's existing functionality.

To do this we override the onError method - we can add this to our Universal solution because in the Classic toolkit this method will just sit idle, whereas, in the Modern toolkit, the code we added in the last step will be unused. This isn't ideal but is neater than having lots of code spread around the project.

If you look in the framework's source we can see the onError function is defined as below:

Replacing the Broken Image

Now that we can tell when an image hasn't loaded properly we can then replace it with an image that we know is there and will serve as an adequate fallback. We do this by simply setting the src config (using the setSrc setter) in this error event handler and have that one display instead.

Rather than hardcode this value we will add a config value - fallbackImg - which can then we easily customised on a per image basis. In this case I've used my default Gravatar profile image.

Classic

For the Classic toolkit we simply make this call in the onImageError method.

When we now run our example we can see the two image requests being made and our console.log call happening in between them.

image

Modern

To add this functionality to the Modern toolkit we must replace part of the onError method and call the setSrc function instead.

This will replicate the Classic toolkit's functionality in the Modern. Perfect!

Complete Code

The complete code for the component can be found below. You're most welcome to use it wherever you like!

To see the code in action or to have a play with it, check out this Sencha Fiddle - https://fiddle.sencha.com/#fiddle/14dc

Conclusion

So there we are! We've created an extremely simple method of ensuring our app never has any dead images, keeping it much more professional looking and our users happy! All the while making it Universal so it works across both the Classic and Modern Toolkits.

Taking it Further...

I've kept this very simple to demonstrate the process but we could extend it further to have more features for example....

A pre-loaded placeholder to be shown before our real image has loaded. To do this we could immediately render the pre-loaded image and then load our real image in memory (using the JavaScript Image class), once that has loaded then we can swap the URLs.

Enhance the class so that it only loads the real image when it comes into view - this could be really useful when being included in long lists as it will keep the data transfer overhead to a minimum - perfect for mobile devices!

Let me know if you've solved this problem in a different/better way in the past - I'd love to hear from you!

Filed under