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>