I am building an Angular message component:
<app-info-card>
my message here
</app-info-card>
Here's my component:
import {AfterViewInit, Component, ContentChild, ElementRef, Input, OnInit} from '@angular/core';
@Component({
selector: 'app-info-card',
templateUrl: './info-card.component.html',
styleUrls: ['./info-card.component.css']
})
export class InfoCardComponent implements OnInit, AfterViewInit {
@ContentChild('app-info-card') messageRef: ElementRef;
message: string;
constructor() {
}
ngOnInit() {
}
ngAfterViewInit() {
this.message = this.messageRef.nativeElement.innerHTML;
console.log(this.messageRef.nativeElement.innerHTML);
}
}
This gives me an error that messageRef is undefined. I'm trying to get the inner text from the component selector "my message here" into the message field of the component. Is there a way I can do this without adding attributes?
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>
I know this question is old, but I found the solution to this question without introducing the additional (inner/wrapped) component directive.
Inside the template of the component that needs to access the content as string, you need to use the wrapped combination of ng-template
and ng-content
. Then, grab the pointer to the template using the ViewChild
. The trick is that the template does not render by itself, while its content is still populated.
Template of the component that needs the content as string without rendering it:
<ng-template #template>
<ng-content></ng-content>
</ng-template>
Inside that same component's ts code, you get the content as a TemplateRef
that you can render anywhere you want:
@ViewChild('template') templateRef!: TemplateRef<unknown>;
Finally, you can pass the content exactly as you wanted to do:
<app-info-card>
my message here
</app-info-card>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With