-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: set up Hammer outside of Angular to reduce CDs (#443)
- Loading branch information
Showing
2 changed files
with
88 additions
and
34 deletions.
There are no files selected for viewing
58 changes: 58 additions & 0 deletions
58
libs/ngu/carousel/src/lib/ngu-carousel/ngu-carousel-hammer-manager.ts
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import { Injectable, NgZone, OnDestroy } from '@angular/core'; | ||
import { Observable, Subject, defer, fromEvent, map, shareReplay, takeUntil } from 'rxjs'; | ||
|
||
@Injectable({ providedIn: 'root' }) | ||
export class NguHammerLoader { | ||
private _hammer$ = defer(() => import('hammerjs')).pipe( | ||
shareReplay({ bufferSize: 1, refCount: true }) | ||
); | ||
|
||
load() { | ||
return this._hammer$; | ||
} | ||
} | ||
|
||
@Injectable() | ||
export class NguCarouselHammerManager implements OnDestroy { | ||
private _destroy$ = new Subject<void>(); | ||
|
||
constructor(private _ngZone: NgZone, private _nguHammerLoader: NguHammerLoader) {} | ||
|
||
ngOnDestroy(): void { | ||
this._destroy$.next(); | ||
} | ||
|
||
createHammer(element: HTMLElement): Observable<HammerManager> { | ||
return this._nguHammerLoader.load().pipe( | ||
map(() => | ||
// Note: The Hammer manager should be created outside of the Angular zone since it sets up | ||
// `pointermove` event listener which triggers change detection every time the pointer is moved. | ||
this._ngZone.runOutsideAngular(() => new Hammer(element)) | ||
), | ||
// Note: the dynamic import is always a microtask which may run after the view is destroyed. | ||
// `takeUntil` is used to prevent setting Hammer up if the view had been destroyed before | ||
// the HammerJS is loaded. | ||
takeUntil(this._destroy$) | ||
); | ||
} | ||
|
||
on(hammer: HammerManager, event: string) { | ||
return fromEvent(hammer, event).pipe( | ||
// Note: We have to re-enter the Angular zone because Hammer would trigger events outside of the | ||
// Angular zone (since we set it up with `runOutsideAngular`). | ||
enterNgZone(this._ngZone), | ||
takeUntil(this._destroy$) | ||
); | ||
} | ||
} | ||
|
||
function enterNgZone<T>(ngZone: NgZone) { | ||
return (source: Observable<T>) => | ||
new Observable<T>(subscriber => | ||
source.subscribe({ | ||
next: value => ngZone.run(() => subscriber.next(value)), | ||
error: error => ngZone.run(() => subscriber.error(error)), | ||
complete: () => ngZone.run(() => subscriber.complete()) | ||
}) | ||
); | ||
} |
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