@taiga-ui/event-plugins is a tiny (1KB gzip) library for optimizing change detection cycles for performance sensitive events (such as touchmove, scroll, drag etc.) and declarative preventDefault() and stopPropagation().
-
Add
NG_EVENT_PLUGINSto your app providers:bootstrapApplication(AppComponent, { providers: [NG_EVENT_PLUGINS], });
-
Use new modifiers for events in templates and in
@HostListener:.stopto call stopPropagation() on event.preventto call preventDefault() on event.selfto skip bubbled events.zonelessto call event handler outside Angular'sNgZone.captureto listen to events in capture phase.passiveto add passive event listener.onceto remove event listener after first callbackresizeto watch for elements changing dimensions withResizeObserver.debounce~<delay>to delay the execution of the event handler for a specified time (ms or s).throttle~<delay>to limits how often the event handler can run for a specified time (ms or s)
For example:
<div (mousedown.prevent)="onMouseDown()">Clicking on this DIV will not move focus</div>
<div (click.stop)="onClick()">Clicks on this DIV will not bubble up</div>
<div (mousemove.zoneless)="onMouseMove()">Callbacks to mousemove will not trigger change detection</div>
<div (click.capture.stop)="onClick()"> <div (click)="never()">Clicks will be stopped before reaching this DIV</div> </div>
<button (click.debounce~300ms)="onClick()">Debounced Click</button> <button (click.debounce~2s)="onClick()">Debounced Click</button>
<button (click.throttle~300ms)="onClick()">Throttled Click</button> <button (click.throttle~2s)="onClick()">Throttled Click</button>
-
You can also re-enter
NgZoneand trigger change detection, using@shouldCalldecorator that takes a predicate function as argument:
<div (scroll.zoneless)="onScroll($event.currentTarget)">
Scrolling this DIV will only trigger change detection and onScroll callback if it is scrolled to bottom
</div>import {shouldCall} from '@taiga-ui/event-plugins';
export function scrollFilter({
scrollTop, scrollHeight, clientHeight
}: HTMLElement): boolean {
return scrollTop === scrollHeight - clientHeight;
}
// ...
@shouldCall(scrollFilter)
onScroll(_element: HTMLElement): void {
this.someService.requestMoreData();
}- Angular global events only support
body,windowanddocument. You can listen to events on any global object with these plugins by replacing:with>symbol, for example:
@HostListener('visualViewport>resize', ['$event.target'])
onPinchZoom({ scale }: VisualViewport) {
console.log(scale)
}- iOS currently doesn't support the
contextmenuevent. Instead, you can use a customlongtapevent. This event captures thecontextmenuevent on non-iOS devices and simulates similar behavior on iOS devices.
<div (longtap)="showContextMenu($event.detail.clientX, $event.detail.clientY)">Div with context menu</div>All examples above work the same when used with
@HostListenerandCustomEvent
-
Predicate is called with the same arguments as the decorated method and in the context of class instance (has access to
this) -
Decorated method will be called and change detection triggered if predicate returns
true. -
.zonelessmodifier will not work with built-in keyboard pseudo-events, such askeydown.enterorkeydown.arrowDownsince Angular re-entersNgZoneinside internal handlers.
You can try this interactive demo
You can also read this detailed article explaining how this library works
@taiga-ui/event-plugins is a part of Taiga UI libraries family which is backed and used by a large enterprise. This means you can rely on timely support and continuous development.
🆓 Feel free to use our library in your commercial and private applications
All @taiga-ui/event-plugins packages are covered by Apache 2.0
Read more about this license here