Check if output is present on component

Viewed 1616

Consider the following component:

@Component({
  selector: 'app-test'
  template: 'Hello!'
}}
export class TestComponent {
  @Output() readonly selectionChange = new EventEmitter<SomeTypeHere>();
}

With the call:

<app-test (selectedChange)="selectedChangeHandler($event)"></app-test>

Note that I've written selectedChange instead of the correct output name selectionChange. Angular 9 with the flag strictTemplates enabled didn't help me at all. It failed silently. The interesting part is that if I do the same thing for @Input, the app catch the error(s) and doesn't compile.

Is there any way to throw an error if I try to "listen" an inexistent @Output?

4 Answers

There is no error thrown because the event binding in Angular is used not only with @Outputs and EventEmitters, but also to listen to the DOM events such as click, keyup, etc. It could even be used to listen to custom events. For example, if you create and emit a custom event in the child component:

constructor (private el: ElementRef) {}
ngOnInit(): void {
    const domEvent = new CustomEvent('selectedChange', { custom: true });
    this.el.nativeElement.dispatchEvent(domEvent);
}

Then in the parent component you can catch it by its name:

<app-test (selectedChange)="selectedChangeHandler($event)"></app-test>

Angular uses target.addEventListener(type, listener [, options]); internally (you can make sure of it looking at the links below), where type could be any string.

That's why it doesn't throw any exception if it doesn't find matching @Outputs.

listenToElementOutputs

DefaultDomRenderer2.listen

EventManager.addEventListener

DomEventsPlugin.addEventListener

There is no direct solution to your problem, however some cases can be covered.

  1. If you have any output that is used in 100% of places like button click event then you can make it part of the selector i.e. selector: 'app-test[selectionChange]'. Also you can do this for example: selector: 'app-test[selectionChange]', app-test[click]' meaning click or selectionChange is required.
  2. If you are refactoring code and rename output i.e. selectionChange to selectedChange then you can use this selector: selector: 'app-test:not([selectionChange])' to force users to update.

This should work for you.

ngOnInit() : void {
 if(this.selectionChange.observers.length > 0){
   console.log("Nice coding");
 }else{
  console.log("Something is wrong!!");
}

If you are using VS Code you can install this extension: Angular Language Service will throw a warning when a method or property is not defined. This extension works with both, outputs and inputs (and attrs, etc...).

Identifier 'XXXvalidateProvider' is not defined.

Related