Skip to content

Commit

Permalink
feat: FallbackImageController - update the controller to support fail…
Browse files Browse the repository at this point in the history
…ing when the placeholder also fails. Also works more consistently in race-conditions when the image has already loaded when the controller mounts.
  • Loading branch information
Sub-Xaero committed Apr 28, 2021
1 parent d3051bf commit 1fd682d
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 12 deletions.
15 changes: 10 additions & 5 deletions docs/docs/controllers/fallback_image_controller.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ title: FallbackImageController
import NoActions from "../_partials/no-actions.md";
import NoTargets from "../_partials/no-targets.md";
import NoClasses from "../_partials/no-classes.md";
import NoEvents from "../_partials/no-events.md";

## Purpose

Expand Down Expand Up @@ -36,24 +35,30 @@ If an image fails to load from the source, provide a fallback image, or hide it

## Events

| Event | When | Dispatched on | `event.detail` |
| --- | --- | --- | --- |
| `fallback-image:placeholder` | When the image fails to load and falls back to the placeholder | The controller root element | - |
| `fallback-image:fail` | When the image and the placeholder (if any) fails to load | The controller root element | - |

<NoEvents/>

## Side Effects

None

- Sets an `onError` handler for the mounted `<img>` tag.
- Sets the style of the image to be `display: none` if the image fails to load.


## How to Use

If an image fails to load, the controller will either try to set the `src` to a placeholder image you provide, or hide the image using `display: none`.

If the placeholder URL you provide *also* fails to load, the controller will fall back to the default behaviour of hiding the element.

<iframe
src="https://codesandbox.io/embed/fallbackimagecontroller-poh1m?fontsize=14&hidenavigation=1&theme=dark"
style={{width: "100%", height: "500px", border: "0", borderRadius: "4px", overflow: "hidden"}}
sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"
/>

*Please note:* If the placeholder URL you provide fails to load, there is no fallback - the borked image icon may still show. This controller relies on the `onError` behaviour of the `img` tag, but it may only run once.



33 changes: 26 additions & 7 deletions src/controllers/media/fallback_image_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,35 @@ export class FallbackImageController extends BaseController {
declare readonly placeholderValue: string;
declare readonly hasPlaceholderValue: boolean;

initialize() {
this._loadedSuccessfully = this._loadedSuccessfully.bind(this);
this._fail = this._fail.bind(this);
}

connect() {
let element = this.el as HTMLImageElement;

element.onerror = () => {
if (this.hasPlaceholderValue) {
element.src = this.placeholderValue;
} else {
element.style.display = "none";
}
};
element.onerror = this._fail;
if (element.complete && !this._loadedSuccessfully()) {
this._fail();
}
}

private _fail() {
let element = this.el as HTMLImageElement;

if (this.hasPlaceholderValue && element.src !== this.placeholderValue) {
this.dispatch(element, "fallback-image:placeholder");
element.src = this.placeholderValue;
element.onerror = this._fail;
} else {
this.dispatch(element, "fallback-image:fail");
element.style.display = "none";
}
}

private _loadedSuccessfully(): boolean {
let element = this.el as HTMLImageElement;
return element.naturalHeight > 0 && element.naturalWidth > 0;
}
}

0 comments on commit 1fd682d

Please sign in to comment.