Skip to content

is a tiny library for optimizing change detection cycles for performance sensitive events

License

Notifications You must be signed in to change notification settings

taiga-family/ng-event-plugins

Angular Event Plugins

npm version npm bundle size Coverage Status telegram chat

@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().

How to use

  1. Add NG_EVENT_PLUGINS to your app providers:

    bootstrapApplication(AppComponent, {
      providers: [NG_EVENT_PLUGINS],
    });
  2. Use new modifiers for events in templates and in @HostListener:

    • .stop to call stopPropagation() on event
    • .prevent to call preventDefault() on event
    • .self to skip bubbled events
    • .silent to call event handler outside Angular's NgZone
    • .capture to listen to events in capture phase
    • .passive to add passive event listener
    • .once to remove event listener after first callback
    • resize to watch for elements changing dimensions with ResizeObserver

    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.silent)="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>
  3. You can also re-enter NgZone and trigger change detection, using @shouldCall decorator that takes a predicate function as argument:

<div (scroll.silent)="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();
}
  1. Angular global events only support body, window and document. 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)
}
  1. iOS currently doesn't support the contextmenu event. Instead, you can use a custom longtap event. This event captures the contextmenu event 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 @HostListener and CustomEvent

Important notes

  • 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.

  • .silent modifier will not work with built-in keyboard pseudo-events, such as keydown.enter or keydown.arrowDown since Angular re-enters NgZone inside internal handlers.

Demo

You can try this interactive demo

You can also read this detailed article explaining how this library works

Maintained

@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.

License

🆓 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