简体   繁体   中英

Angular 9 decorators on abstract base class

I'm working on upgrading my project from Angular 8 to 9, and I've come across a problem with new requirements when extending classes.

According to Angular's documentation :

Undecorated base classes using Angular features

As of version 9, it's deprecated to have an undecorated base class that:

  • uses Angular features
  • is extended by a directive or component

Angular lifecycle hooks or any of the following Angular field decorators are considered Angular features:

  • @Input()
  • @Output()
  • @HostBinding()
  • @HostListener()
  • @ViewChild() / @ViewChildren()
  • @ContentChild() / @ContentChildren()

For @Component decorators, it requires a template or templateURL on the base class. Adding either causes the child class to not render it's template.

For example, the following result in nothing rendering on the view:

@Component({
  template: ''
})
export abstract class BaseComponent<T extends AbstractSuperEntity> extends Toggler implements OnChanges {
  @Input()
  year: number | string

  constructor(service: MyService) {

  }

  ngOnChanges() {
  }
}

@Component({
  templateUrl: 'my.component.html',
  selector: 'my-component'
})
export class MyComponent extends BaseComponent<AbstractSuperEntity> {

  constructor(service: MyService) {
    super(service);
  }

}

I tried changing the base class to use templateUrl pointing to an empty html, but that doesn't work either.

You have to add an empty @Directive() decorator. As far as I know, that should be enough:

@Directive()
export abstract class BaseComponent<T extends AbstractSuperEntity> extends Toggler implements OnChanges {
  @Input()
  year: number | string

  constructor(service: MyService) {

  }

  ngOnChanges() {
  }
}

It's been quite a while after this question was asked, but I stumbled upon it so this might be useful to others as well.

You don't necessarily have to add the @Directive decorator. If it's a component just use @Component instead. That should work. See the following stackblitz example:

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

In the question it's unclear what's wrong. An error message would help.

What also might've gone wrong is that the OP was not implementing the lifecycle method on the super call:

import { Component, OnInit, Input } from '@angular/core';

@Component({
  template: '',
})
export abstract class BaseComponent implements OnInit {
  @Input()
  year: number | string;

  constructor() {}

  ngOnInit() {
    console.log('This will only work if you call it in the child component');
  }
}

@Component({
  selector: 'child-component',
  template: '<p>test, year: {{ year }}</p>',
})
export class ChildComponent extends BaseComponent implements OnInit {
  constructor() {
    super();
  }

  ngOnInit() {
    super.ngOnInit();
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM