Search code examples
angularangular-componentsangular-decoratorangular-inheritance

Base class for component with a decorated method is not being picked up in the component that inherits from it


I'm using this code in my component to have a confirmation before the user refreshes the page, to avoid losing changes by mistake:

  @HostListener('window:beforeunload', ['$event'])
  unloadNotification($event: any) {
    if (!this.canDeactivate()) {
     $event.returnValue = '';
     $event.preventDefault();
    }
  }

To avoid duplicating that code in other components I wanted to create a base class like

@Injectable()
export abstract class ComponentCanDeactivate {
  abstract canDeactivate(): boolean;

  @HostListener('window:beforeunload', ['$event'])
  unloadNotification($event: any) {
    if (!this.canDeactivate()) {
      $event.returnValue = '';
      $event.preventDefault();
    }
  }

but now the components extending this base class, don't seem to be listening to the beforeunload event. Is the decorator not being picked by Angular because it is on the base class? I see this work in this: example using angular 11, and I'm using angular 13. don't know if that changed the behavior or if I'm missing something


Solution

  • You need the abstract class to be a Component rather than an Injectable

    @Component({ template: '' })
    export abstract class ComponentCanDeactivate {
    

    https://stackblitz.com/edit/angular-ivy-xsmfdn?file=src/app/concrete/concrete.component.ts

    Angular supports inheriting HostListener but seems to get confused when you mix decorators like that.