Using directive output in Drective Composition API

62 Views Asked by At

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....
  }
}
2

There are 2 best solutions below

0
Chellappan வ On BEST ANSWER

You can use hostListener decorator to listen hostDirectives output.

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

Example

2
Naren Murali On

I am able to import the directive through the constructor, since its binded to the element!

Just to make sure I created two directives and its working fine!

binded 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 />

binded 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