2

The Angular Docs show that you can use Directive Composition API even when directive has outputs. However, it seems that directive's outputs become component's outputs. I'd like to use directive's output within the component to which I'm attaching the directive. Is there any way to do that?

@Component({ standalone: true, selector: 'admin-menu', template: 'admin-menu.html', hostDirectives: [{ directive: MenuBehavior, inputs: ['menuId'], outputs: ['menuClosed'], }], }) export class AdminMenu { someMethod() { // use menuClosed here.... } } 

3 Answers 3

2

You can use hostListener decorator to listen hostDirectives output.

export class AdminMenu { @HostListener('menuClosed',['$event']) onMenuClosed(e:{closed:boolean}){ console.log('Closed',e); } } 

Example

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

Comments

1

As per the latest recommendation from the official documentation:

Always prefer using the host property over @HostBinding and @HostListener. These decorators exist exclusively for backwards compatibility.

It seems the proper way to do it nowadays is like this:

@Component({ standalone: true, selector: 'admin-menu', template: 'admin-menu.html', hostDirectives: [{ directive: MenuBehavior, inputs: ['menuId'], outputs: ['menuClosed'], }], host: { '(menuClosed)': 'someMethod()', } }) export class AdminMenu { someMethod() { // use menuClosed here.... } } 

Comments

1

I am able to import the directive through the constructor, since it's bound to the element.

Just to make sure I created two directives and it's working fine!

Bound component html

<p>test works!</p> <br /><br /><br /> test directive output {{ output }} <br /><br /><br /><br /> <br /> qwerty directive output {{ output1 }}<br /><br /><br /><br /> 

Bound component ts

import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; import { QwertyDirective } from '../qwerty.directive'; import { TestDirective } from '../test.directive'; @Component({ selector: 'app-test', standalone: true, hostDirectives: [ { directive: TestDirective, inputs: ['menuId'], outputs: ['emitter'], }, { directive: QwertyDirective, inputs: ['menuId'], outputs: ['emitter'], }, ], templateUrl: './test.component.html', styleUrls: ['./test.component.css'], }) export class TestComponent implements OnInit { @Input('menuId') menuId!: string; @Output() emitter: EventEmitter<any> = new EventEmitter<any>(); output = ''; output1 = ''; constructor( private testDir: TestDirective, private qwertyDir: QwertyDirective ) {} ngOnInit() { this.testDir.emitter.subscribe((val: any) => { this.output = val; }); this.qwertyDir.emitter.subscribe((val: any) => { this.output1 = val; }); } } 

directive

import { Directive, EventEmitter, Input, Output } from '@angular/core'; import { interval } from 'rxjs'; @Directive({ selector: '[appTest]', standalone: true, }) export class TestDirective { @Input('menuId') menuId!: string; @Output() emitter: EventEmitter<any> = new EventEmitter<any>(); constructor() { interval(1000).subscribe(() => { this.emitter.emit(Math.random() + ' ' + this.menuId); }); } } 

main.ts

import { Component } from '@angular/core'; import { bootstrapApplication } from '@angular/platform-browser'; import 'zone.js'; import { QwertyDirective } from './qwerty.directive'; import { TestDirective } from './test.directive'; import { TestComponent } from './test/test.component'; @Component({ selector: 'app-root', standalone: true, imports: [TestDirective, TestComponent, QwertyDirective], template: ` <app-test [menuId]="name" (emitter)="emitter($event)"></app-test> output {{output}} `, }) export class App { name = 'Angular'; output = ''; output1 = ''; emitter(event: any) { this.output = event; } } bootstrapApplication(App); 

stackblitz

2 Comments

Interesting example, thanks. I did not know that when you inject the directive into component, it will inject the same instance as the one used on the host.
@mnj as I posted this answer, i saw the one below it and it looks cleaner, go for the second approach if you want cleaner code :) the second one is the cleaner correct answer

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.