angularangular2-services

Is it possible to use HostListener in a Service? Or how to use DOM events in an Angular service?


I want to create a service which detects all keyboard input, translates the key strokes into actions based on a configurable mapping, and exposes observables which various elements can bind to to react to specific key presses.

The following is a simplification of my code so far, it worked when HostListener was in a component, but now I've moved it into a service it never fires even though it is definitely initialised. Is it not possible to detect input like this in a service?

import { Injectable, HostListener } from '@angular/core';

import { Subject } from 'rxjs/Subject';

@Injectable()
export class InputService {

    @HostListener('window:keydown', ['$event'])
    keyboardInput(event: any) {
        console.log(event);
    }
}

Solution

  • Seems like its not possible to use HostListener in a service.

    UPDATE

    like Stanislasdrg Reinstate Monica wrote, there's a more elegant and more angular way using the renderer..

    @Injectable()
    export class MyMouseService implements OnDestroy {
      private _destroy$ = new Subject();
    
      public onClick$: Observable<Event>;
    
      constructor(private rendererFactory2: RendererFactory2) {
        const renderer = this.rendererFactory2.createRenderer(null, null);
    
        this.createOnClickObservable(renderer);
      }
    
      ngOnDestroy() {
        this._destroy$.next();
        this._destroy$.complete();
      }
    
      private createOnClickObservable(renderer: Renderer2) {
        let removeClickEventListener: () => void;
        const createClickEventListener = (
          handler: (e: Event) => boolean | void
        ) => {
          removeClickEventListener = renderer.listen("document", "click", handler);
        };
    
        this.onClick$ = fromEventPattern<Event>(createClickEventListener, () =>
          removeClickEventListener()
        ).pipe(takeUntil(this._destroy$));
      }
    }
    

    live-demo: https://stackblitz.com/edit/angular-so4?file=src%2Fapp%2Fmy-mouse.service.ts

    OLD

    You could use the old way window.addEventListener like @yurzui pointed out already.

    https://plnkr.co/edit/tc53cvQDfLHhaR68ilKr?p=preview

    import {Component, NgModule, HostListener, Injectable} from '@angular/core'
    import {BrowserModule} from '@angular/platform-browser'
    
    @Injectable()
    export class MyService {
    
      constructor() {
        window.addEventListener('keydown', (event) => {
          console.dir(event);
        });
      }
    
    }
    
    @Component({
      selector: 'my-app',
      template: `
        <div>
          <h2>Hello {{name}}</h2>
        </div>
      `,
    })
    export class App {
    
      constructor(private _srvc: MyService) {
        this.name = 'Angular2'
      }
    }
    
    @NgModule({
      imports: [ BrowserModule ],
      declarations: [ App ],
      providers: [MyService],
      bootstrap: [ App ]
    })
    export class AppModule {}