Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@baetheus
Created April 23, 2019 19:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save baetheus/b1eb474146d1ccdea95cb712f5a631e6 to your computer and use it in GitHub Desktop.
Save baetheus/b1eb474146d1ccdea95cb712f5a631e6 to your computer and use it in GitHub Desktop.
Image fallback
import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, Output, Renderer2 } from '@angular/core';
import { fromEvent, merge, Observable, Subscription } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
const requestImage = (src: string) => {
const img = new Image();
img.src = src;
return merge(fromEvent(img, 'error'), fromEvent(img, 'load')).pipe(
map(evt => {
if (evt.type === 'error') {
throw new Error('Unable to load image.');
}
return src;
}),
);
};
const tryImages = (srcs: string[]): Observable<any> => {
const [head, ...tail] = srcs;
return tail.length > 0 ? requestImage(head).pipe(catchError(_ => tryImages(tail))) : requestImage(head);
};
@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'loda-imgp',
exportAs: 'imgp',
styleUrls: ['./imgp.component.scss'],
template: ``,
})
export class LodaImgpComponent {
@Input()
src: string | string[] = [];
@Input()
fallbackImage = '/assets/img/placeholder.png';
@Output()
readonly error = new EventEmitter<ErrorEvent>();
prevSub?: Subscription;
/**
* Set background image of host container to src
*/
readonly setImage = (src: string) => {
this.renderer.setStyle(this.element.nativeElement, 'backgroundImage', `url(${src})`);
};
/**
* Try src or srcs and fallback image until first working image is found.
*/
readonly findImage = () => {
const srcs = typeof this.src === 'string' ? [this.src, this.fallbackImage] : [...this.src, this.fallbackImage];
if (!!this.prevSub) {
this.prevSub.unsubscribe();
}
this.prevSub = tryImages(srcs).subscribe(img => this.setImage(img), err => this.error.next(err));
};
ngOnInit() {
this.findImage();
}
ngOnChanges() {
this.findImage();
}
constructor(readonly element: ElementRef, readonly renderer: Renderer2) {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment