Is there a way to check for @Output wire up from within a component in Angular?

AngularTypescript

Angular Problem Overview


In the ngOnInit method of a component the @Input values will have been bound so you can check those properties on the component, but there doesn't seem to be a way to check @Output event bindings. I want to be able to know if the @Output was wired up on the component or not.

(using Angular and TypeScript)

import {Component, Output, EventEmitter} from '@angular/core';

@Component({
    selector: 'sample',
    template: `<p>a sample</p>`
})
export class SampleComponent {
    @Output() cancel = new EventEmitter();
	
	ngOnInit() {
		// would like to check and see if cancel was used
		// on the element <sample (cancel)="doSomething()"></sample> 
		// or not <sample></sample>
	}
}

Angular Solutions


Solution 1 - Angular

Same approach as user1448982 but without using the ObservableWrapper that is meant to be platform code that is not exposed for use via the api.

(Using Angular 2 RC1 and TypeScript)
Note: This only started working from 2.0.0-beta.16 and greater

import {Component, Output, EventEmitter} from '@angular/core';

@Component({
    selector: 'sample',
    template: `<p>a sample</p>`
})
export class SampleComponent {
    @Output() cancel = new EventEmitter();
    private isCancelUsed = false;

    ngOnInit() {
        this.isCancelUsed = this.cancel.observers.length > 0;
    }
}

Plunker

The ObservableWrapper.hasSubscribers method does this line internally, so you can just do the same thing here.

When using TypeScript you will get a transpile time error if Angular ever ends up changing the EventEmitter from a Subject (which is part Observable, thus the .observers property).

Update (03 / 2022)

The observers attribute is deprecated since rxjs v7. Instead of checking the length of the observers array, you can now use a boolean that indicates if the subject is in use.

// Old approach
this.isCancelUsed = this.cancel.observers.length > 0;

// New approach
this.isCancelUsed = this.cancel.observed;

Solution 2 - Angular

Angular 12 removed the EventEmitter#observables field so the accepted answer is no longer valid.

An alternative solution for now would be to cast to a Subject instead:

get hasOutputEventSubscriber() {
    return (this.cancel as Subject).observers;
}

Note that this property is also deprecated and will be removed in rxjs v8. A future-proof solution would be to write a custom wrapper class for the EventEmitter.

Solution 3 - Angular

The following code should work:

import {Component, Output, EventEmitter, OnInit} from 'angular2/core';
import {ObservableWrapper} from 'angular2/src/facade/async';

@Component({
    selector: 'sample',
    template: `<p>a sample</p>`
})
export class SampleComponent implements OnInit {
    @Output() cancel: EventEmitter<any> = new EventEmitter();

    private isCancelUsed: boolean;

    ngOnInit(): void {
        this.isCancelUsed = ObservableWrapper.hasSubscribers(this.cancel);
    }
}

Solution 4 - Angular

Here is a future proof example that does not rely on any internals of Angular or rxjs. This is a simple wrapper around EventEmitter that exposes a subscriberCount property that is automatically incremented/decremented as subscribers are added/removed.

class WatchedEventEmitter extends EventEmitter<any> {
    private _subscriberCount = 0;
    get subscriberCount(): number {
        return this._subscriberCount;
    }

    subscribe(next?: (value: any) => void, error?: (error: any) => void, complete?: () => void): Subscription {
        ++this._subscriberCount;
        return super.subscribe(next, error, complete);
    }

    unsubscribe() {
        --this._subscriberCount;
        super.unsubscribe();
    }
}

Usage example:

@Component({template: `
    {{click.subscriberCount|json}}
    <span *ngIf="cancel.subscriberCount">
        <button mat-icon-button (click)="cancel.emit()">Click Me</button>
    </span>
    
    <span *ngIf="!cancel.subscriberCount">No Subscribers</span>
`})
export class SomeComponent {
    @Output() cancel = new WatchedEventEmitter();
}

Solution 5 - Angular

as of now current version Angular 13 to check if is there any observer/callback is provided you can use this.cancel.observed which will return boolean

import {Component, Output, EventEmitter} from '@angular/core';

@Component({
    selector: 'sample',
    template: `<p>a sample</p>`
})
export class SampleComponent {
    @Output() cancel = new EventEmitter();
    private isCancelUsed = false;

    ngOnInit() {
        this.isCancelUsed = this.cancel.observed;
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionJustin SchwartzenbergerView Question on Stackoverflow
Solution 1 - AngularJustin SchwartzenbergerView Answer on Stackoverflow
Solution 2 - AngularxaviertView Answer on Stackoverflow
Solution 3 - Angularuser1448982View Answer on Stackoverflow
Solution 4 - AngularDan MorphisView Answer on Stackoverflow
Solution 5 - AngularVikas KandariView Answer on Stackoverflow