Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent or cancel change detection on global keydown events

Tags:

angular

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

like image 547
ConnorsFan Avatar asked Apr 12 '18 20:04

ConnorsFan


People also ask

What is Keydown enter event?

The keydown event is fired when a key is pressed. Unlike the deprecated keypress event, the keydown event is fired for all keys, regardless of whether they produce a character value. The keydown and keyup events provide a code indicating which key is pressed, while keypress indicates which character was entered.

How do you get the value of a Keydown event?

The simple solution: just use the keyup event (and not the keydown event). This will give you the latest value after the user typed the latest character. That resolves the issue.

What is Keyup and Keydown in angular?

The KeyDown event is triggered when the user presses a Key. 2. The KeyUp event is triggered when the user releases a Key. 3. The KeyPress event is triggered when the user presses & releases a Key.

How do you use Keydown?

keydown – on pressing the key (auto-repeats if the key is pressed for long), keyup – on releasing the key.


2 Answers

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.

like image 96
ConnorsFan Avatar answered Nov 15 '22 07:11

ConnorsFan


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

like image 36
ashfaq.p Avatar answered Nov 15 '22 05:11

ashfaq.p