1

I stopped using the @Output() decorators since the new output() function got released.

I got my dummy component:

export class TaskComponent implements OnInit {
    readonly taskStarted = output<number>();

    taskStartedClick(id: number) {
        this.taskStarted.emit(id);
    }
}

I am using it in my parent component:

<app-task (taskStarted)="doStuff($event)"></app-task>

I am trying to figure out whether the emitted event is observed by the parent component or not.

Using the old @Output decorator, you could go ahead and check whether it is observed or not, e.g:

ngOnInit() {
    const isObserved = this.taskStarted.observed;
}

But I can't do the same with output(), since it is an OutputEmitterRef and not an EventEmitter.

Does anybody else know perhaps another solution or an alternative? I have tried and searched in the internet, but it is very difficult to find solutions for the new output() function, instead you get mainly solutions for the @Output() decorator.

2
  • 1
    There is no direct API to check if the output created using output() is observed. This is likely by design to align with the simplified and more declarative style of standalone components, where internal components shouldn't generally care about whether the parent listens to events.
    – tepalia
    Commented yesterday
  • @tepalia I see. I get your point as well. Although it would be useful, in case a developer forgot to observe the event, so the component could log an error or something.
    – T. Jami
    Commented yesterday

3 Answers 3

1

The recommendation today is to have an Observable (which has the observed property and to use outputFromObservable.

-1

Well, you're right, the newest output() is not the same, as before.

🔍 So, how to check if the output is being observed? As of now, there's no direct API like .observed on OutputEmitterRef. The Angular team has not (yet) exposed a way to detect whether an output from output() is connected to a listener in the template.

✅ The safest way: Right now, you should emit regardless of whether it's observed — that’s the design philosophy of this new model. It’s leaner and assumes fire-and-forget semantics.

But if you really need to check if it’s connected (e.g., for optimization or debugging), here are some ideas/workarounds:

🛠 Workaround Option: Use @ViewChild in the parent In the parent component, grab a reference to the child:

@ViewChild(TaskComponent) taskComp!: TaskComponent;

Then in ngAfterViewInit(), you can monkey-patch or wrap taskStarted.emit() and see if it gets called.

But… it's still not ideal and not reactive.

💡 Alternative Approach: Use a wrapper or helper If you're emitting many events but want to track who listens, you could define your own helper:

function outputWithObserved<T>() {
  const emitter = output<T>();
  let observed = false;

  // Expose a setter to flag when someone subscribes
  const markObserved = () => { observed = true; };

  return {
    emitter,
    emit: (value: T) => emitter.emit(value),
    markObserved,
    get isObserved() { return observed; }
  };
}

In the parent component, you'd then call .markObserved() on init.

But this is more of a hack — the framework itself doesn’t offer .observed natively for output() (yet).

1
  • 1
    outputWithObserved won't work as the the angular compiler will only recognise output and outputFromObservable as outputs. Commented yesterday
-1

Do not look for a solution:

  1. Just use @Output until it is deprecated.

  2. Raise a request to expose listeners so that the functionality can be achieved.

  3. Do no worry about enforcing listening to output, because it creates tight coupling between the components, it will ruin reusability of the component.

Hacky solution:

You can access the private property listeners and check the length.

@Component({
  selector: 'app-child',
  template: `
        <button (click)="test.emit()">asdf</button>
      `,
})
export class Child {
  test = output();

  ngAfterViewInit() {
    console.log('Number of listeners: ', this.test['listeners']?.length || 0);
  }
}

Full Code:

import { Component, output } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';

@Component({
  selector: 'app-child',
  template: `
        <button (click)="test.emit()">asdf</button>
      `,
})
export class Child {
  test = output();

  ngAfterViewInit() {
    console.log('Number of listeners: ', this.test['listeners']?.length || 0);
  }
}

@Component({
  selector: 'app-root',
  imports: [Child],
  template: `
    <app-child (test)="test()"/>
    <app-child/>
  `,
})
export class App {
  name = 'Angular';

  test() {
    alert('hi');
  }
}

bootstrapApplication(App);

Stackblitz Demo

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.