Martin Parenteau
Martin Parenteau

Reputation: 73731

How to prevent or cancel change detection on global keydown events

While debugging in Chrome to find the source of some slow response in my application, I noticed in the Peformance tab that holding down the Shift key generates repeating keydown events, each one triggering change detection in Angular. The image below shows the Performance tab for one of them. These events are not useful for my application; I know that nothing changes when Shift and Ctrl are pressed by themselves. I only want to know if the key is down when a click event occurs, or when a character or function key is pressed. The extra activity reported in the Performance tab also makes it more difficult to analyze what is of actual interest for my debugging.

Is there a way to prevent or to cancel change detection on global keydown events for keys like Shift and Ctrl?

enter image description here

Upvotes: 6

Views: 5468

Answers (2)

Martin Parenteau
Martin Parenteau

Reputation: 73731

I had actually implemented a global capture keydown event listener to stop the propagation of the keydown events but I had made a mistake identifying the keys. When done correctly, the globalZoneAwareCallback part of the processing was eliminated (on the right on the image in the question); the globalZoneAwareCaptureCallback part remained.


The solution is to stop the propagation of the keydown events in a global event listener which does not itself trigger change detection:

  • Set a global event listener on the keydown event (e.g. in a service)
  • Stop the propagation of the event for the Shift and Ctrl keys
  • Wrap the call to window.document.addEventListener inside NgZone.runOutsideAngular. This is important because addEventListener triggers Angular change detection, contrary to what I first thought.
this.zone.runOutsideAngular(() => {
    window.document.addEventListener("keydown", (event: KeyboardEvent) => { 
        switch (event.which || event.keyCode) {
            case 16:
            case 17: {
                event.stopPropagation();
                break;
            }
        }
    });
});

Thanks to @ashfaq.p and @Nour for the suggestions about NgZone.runOutsideAngular.

Upvotes: 9

ashfaq.p
ashfaq.p

Reputation: 5469

Change detection in angular works using zone.js.

zone.js provides a method called: runOutsideAngularZone().

this.zone.runOutsideAngular(() => {
  window.document.addEventListener('mousemove', this.mouseMove.bind(this));
});

This will allow you to use events like keydown or keyup / mouse move etc outside of angular change detection.

More about this can be found here: zones in angular

Upvotes: 2

Related Questions