Created
April 23, 2019 19:52
-
-
Save baetheus/b1eb474146d1ccdea95cb712f5a631e6 to your computer and use it in GitHub Desktop.
Image fallback
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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