Angular 6: HostListener decorator broken by production build

Viewed 422

My application registers hotkey listeners to allow the user to perform actions with the keyboard only. Here's an example:

  @HostListener('document:keydown.meta.a', ['$event'])
  selectAllHotkey(event: KeyboardEvent) {
    event.preventDefault();
    this.nodes = this.nodes.map(node => {
      node.is_selected = true;
      return node;
    });
  }

This method is inside of a component, and works fine as it is. However, more recently users have requested platform-specific hotkeys (i.e. Control instead of Command). To accomplish this, I created the following function:

export function userAgentToggle<D>(window: Window, pcValue: D, osxValue: D): D {
  if (window.navigator.userAgent.indexOf('Mac OS X') === -1) {
    return pcValue;
  } else {
    return osxValue;
  }
}

All this function does is return one of two arguments based on the user agent. I can apply it like this:

  @userAgentToggle(
    window,
    HostListener('document:keydown.control.a', ['$event']),
    HostListener('document:keydown.meta.a', ['$event'])
  )
  selectAllHotkey(event: KeyboardEvent) {
    // ...
  }

And this works fine in development. Utilizing a user agent switcher, I can verify that each platform is recognized and the appropriate key is listened for. However, it does not work in production. If the application goes through the build process, then none of the event listeners fire.

Normally I'd assume this is a problem with my code, but the fact that it works in dev makes me think this might be a compiler bug. Am I doing something wrong, or should I file an Angular bug ticket?

Edit: I tried shifting things around, and ended up getting an error that said Function calls are not supported in decorators. Googling around revealed this is a constraint of the Angular AoT compiler. I think having this kind of dynamic behavior just isn't supported by Angular's compiler. I got around it by listening only to the keydown event, and adding a second decorator that can filter down to the right key combination.

1 Answers

The solution I found: Put an event binding on keydown in a top HTML element tag (keydown)="yourMethod($event)"

The backend remains the same(use selectAllHotkey() or any other method)

Cause: I seems ng build with --aot parameter does not work with @HostListener (from some version of Angular forward)

Related