42

I want to define a base class for my components to share some features. So i've began with :

export abstract class BaseComponent {
    protected getName(): string;
}

@Component(...)
export class MyComponent extends BaseComponent {
    protected getName(): string {
        return "MyComponent";
    }
}

But after i needed to add some annotations to BaseComponent like @HostListener('window:keydown', ['$event']). So i had to add @Component to BaseComponent to enable angular annotations. Everything was good... Until i tried to compile in production mode with

ng build --prod

:

Cannot determine the module for class BaseComponent

So i've added BaseComponent to @NgModule, but i had :

No template specified for component BaseComponent

So i've added

@Component({template: ''})

But i had :

Argument of type 'typeof BaseComponent' is not assignable to parameter of type 'Type'. Cannot assign an abstract constructor type to a non-abstract constructor type.

So i had remove the "abstract" keyword to compile in production mode my project.

Do you have a solution? I dislike bad conception!

1
  • Did you try just to add the HostListener without doing anything else ? Commented Dec 19, 2017 at 8:09

1 Answer 1

69

Update for Angular 10+

As of Angular 10, when using the IVY compiler, components that are inherited, and which contain Angular functionality, must be decorated with an empty @Directive() decorator.

Read more about it here


There's no need to add @Component() annotations to abstract classes or register them to any module.

It could be that there's something wrong within your code that does not conform to what Angular expects.

I created a demo application using Angular CLI 1.2.7 with the ng new <name> command and extend the AppComponent class as below.

base.component.ts

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

export abstract class BaseComponent {
    @HostListener('click')
    onClick() {
        alert('Click');
    }
}

and

app.component.ts

import { Component } from '@angular/core';
import { BaseComponent } from './base.component';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: [ './app.component.css' ]
})
export class AppComponent extends BaseComponent {
    title = 'app';
}

The app.module class was not changed in any way.

The click handler located in the base component worked without any problems. A AOT compilation using ng build --prod also did not give any errors.

This demo was using angular v5.1.1

Sign up to request clarification or add additional context in comments.

9 Comments

O_o I don't understand, yesterday that's not works... Ok, fine, it's perfect!
The thing is that in case the abstract class is extending another class which is a component, then Angular will require to declare the class in a module, which will subsequently fail since you cannot declare abstract classes in Angular. :(
@CaptainFogetti then there is any solution to over come?
@Walfrat you don't understand the discussion. There is no concrete component to inherit from. We are talking about an abstract superclass which cannot be annotated with the @Component annotation. And yes. Angular 4 smells sometimes, I'll give you that. But still it's a great framework despite it's shortcomings.
+10 for the @Component decorator being unnecessary! Thanks!
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.