Get inner text from angular component selector

you're basically using the ContentChild in a strange way. you are referencing 'app-info-card' in itself as it's own child. from the docs:

You can use ContentChild to get the first element or the directive matching the selector from the content DOM. If the content DOM changes, and a new child matches the selector, the property will be updated.

so, if you want to put some component/directive inside your component and want to access them later, you can use the ContentChild or ContentChildren, in a way like this: (from the same link again)

@Directive({selector: 'pane'})
export class Pane {
  @Input() id: string;
}

@Component({
  selector: 'tab',
  template: `
    <div>pane: {{pane?.id}}</div> 
  `
})
export class Tab {
  @ContentChild(Pane) pane: Pane;
}


@Component({
  selector: 'example-app',
  template: `
    <tab>
      <pane id="1" *ngIf="shouldShow"></pane>
      <pane id="2" *ngIf="!shouldShow"></pane>
    </tab>

    <button (click)="toggle()">Toggle</button>
  `,
})
export class ContentChildComp {
  shouldShow = true;

  toggle() { this.shouldShow = !this.shouldShow; }
}

that being said, you can use it with the class name instead of the selector string. something like this:

@ContentChild(InfoCardComponent) messageRef: InfoCardComponent;

which as i said, is a strange thing to do and would give you the InfoCardComponent component's class itself.

anyway, if you just want to have a component that wraps some block of your elements, you can do two things off the top of my head:

1- using @Input :

if you just want to wrap some text and show it in a special style, you can simply have a property like:

@Input() myMessage: string;

and pass it's value when using InfoCardComponent like this:

<app-info-card [myMessage]="'my message here'"></app-info-card>

and then use it via binding everywhere you want...

2- using <ng-content></ng-content> :

if you want to pass-in to the component, more than just a text and including elements (like <div>s and...), you can use the built-in <ng-content></ng-content> directive which contains everything that's been put inside the initial host element (which in this case, would be your <app-info-card></app-info-card>). and the way it works is that you simply put it inside your template like:

<div>
    <ng-content></ng-content>
</div> 

all of these ways have many details and fit certain cases depending on your need, and i just mentioned a brief case of using them. before using any of them i suggest you reading the docs again.


Based on your answers what you need is to pass in that message into your Child Component. There are different methods, have a look at https://angular.io/guide/component-interaction

I would suggest you work with Input binding in this case. Either with a variable in your parent template

<app-info-card [message]="message"></app-info-card>

Where in the corresponding component you define

private message: string = 'my message here';

Or directly if it's not dynamic (likely not the case)

<app-info-card [message]="'my message here'"></app-info-card>

pay attention to the ' inside

With both ways in your Child Component put it like this:

export class InfoCardComponent implements OnInit {

    @Input('message') message: string;

    ngOnInit() {
        // do whatever other stuff you want
    }

}

You might want to implement OnChanges as well. Let me know if you have further questions.

One alternative is to use content projection.

<app-info-card>my message here</app-info-card>

And in the template of the card, i.e.

<div class="card">
    <ng-content></ng-content>
</div>

As mentioned by @GHB I managed to get this working using a directive. It looks as though it's hard to use the component contents directly but by using a wrapping directive it's possible.

import { Component, OnInit, ContentChild, AfterContentInit, ElementRef, Directive } from '@angular/core';

@Directive({
  selector: 'app-example-code'
})
export class ExampleCodeDirective {}

@Component({
  selector: 'app-example-view',
  templateUrl: './example-view.component.html',
  styleUrls: ['./example-view.component.css']
})
export class ExampleViewComponent implements OnInit, AfterContentInit {  
  @ContentChild(ExampleCodeDirective, { read: ElementRef })
  content: ElementRef;

  constructor() { }

  ngAfterContentInit() {
    if (this.content) {
      console.log(this.content.nativeElement.innerText); 
    }
  }

  ngOnInit() {
  }

}

<app-example-view>
  <app-example-code>
    some text
  </app-example-code>
</app-example-view>

Tags:

Angular