0

It seems that you should use a directive to target a content child from a directive (source).

But why isn't my component recognising the component marked with the directive?

./my.component.ts

import {
  Component,
  Directive,
  ContentChild,
  AfterContentInit
} from "@angular/core";

@Directive({
  selector: "[trigger]"
})
export class TriggerDirective {}

@Component({
  selector: "app-my-component",
  template: ` <ng-content></ng-content> `
})
export class MyComponent implements AfterContentInit {

  @ContentChild(TriggerDirective) trigger: TriggerDirective;

  ngAfterContentInit() {
    console.log("===> ", this.trigger);
    // output: '===> undefined'
  }
}

./my.module.ts

import { NgModule } from "@angular/core";
import { MyComponent, TriggerDirective } from "./my.component";

@NgModule({
  declarations: [MyComponent, TriggerDirective], // declared it here
  exports: [MyComponent]
})
export class MyModule {}

./app.component.ts

import { Component } from "@angular/core";

@Component({
  selector: "app-root",
  template: `
    <h1>Title inside app component.</h1>
    <app-my-component>
      <button #trigger>Click me</button>
    </app-my-component>
  `
})
export class AppComponent {}

./app.module.ts

import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";

import { AppComponent } from "./app.component";
import { MyModule } from "../my-component/my.module";

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, MyModule], // imported the module here
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}
Remi
  • 4,663
  • 11
  • 49
  • 84
  • 1
    `#trigger` actually creates a reference variable to the element, iam not sure if that works to be honest. You can just write `trigger` to make the selector work instead –  Dec 04 '20 at 10:03
  • Ah oké. There also seems to be something else thats wrong. Removed it in this sandbox: https://codesandbox.io/s/flamboyant-boyd-cgrxr – Remi Dec 04 '20 at 10:05
  • 1
    Thank you for the reproducer, you'll need to export the `TriggerDirective` from `MyModule` in order to use it on an element inside of `AppComponent` –  Dec 04 '20 at 10:08
  • Thanks. Got it. I've written up the full example. How can I give you the credit for this answer? – Remi Dec 04 '20 at 10:27
  • I merely gave hints from a first glance, a full fledged answer should include explanation and a working example - just like the one you just posted. –  Dec 04 '20 at 10:31

1 Answers1

0

So the full answer based on the help of @Mike S.

./app.component.ts

import { Component } from "@angular/core";

@Component({
selector: "app-root",
template: `
  <h1>Title inside app component.</h1>
  <app-my-component (submit)="doSomething($event)">
    <!-- 1. use the directive without '#' since that would make it a reference variable -->
      <button trigger>Click me</but
    <button trigger>Click me</button>
  </app-my-component>
`
})
export class AppComponent {}

./trigger.directive.ts

import { Directive } from "@angular/core";

@Directive({
  selector: "[trigger]"
})
export class TriggerDirective {}

./my.component.ts

import { Component, ContentChild, AfterContentInit } from "@angular/core";

import { TriggerDirective } from "./trigger.directive";

@Component({
  selector: "app-my-component",
  template: ` <ng-content></ng-content> `
})
export class MyComponent implements AfterContentInit {
  // 2. declare it as a content child
  @ContentChild(TriggerDirective) trigger: TriggerDirective;

  ngAfterContentInit() {
    console.log("===> ", this.trigger);
  }
}

./my.module.ts

  1. Declare the trigger, and export it for usage in the module where the component lives where you'd like to use it.
import { NgModule } from "@angular/core";
import { MyComponent } from "./my.component";
import { TriggerDirective } from "./trigger.directive";

@NgModule({
  declarations: [MyComponent, TriggerDirective],  // <- declare
  exports: [MyComponent, TriggerDirective] // <- and export
});
export class MyModule {}

./app.module.ts

  1. And finally make sure the entire module is included in the module where you're using it.
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";

import { AppComponent } from "./app.component";
import { MyModule } from "../my-component/my.module";

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, MyModule], // <-
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule {}
Remi
  • 4,663
  • 11
  • 49
  • 84