Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get inner text from angular component selector

Tags:

angular

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?

like image 527
David Findlay Avatar asked Nov 25 '17 04:11

David Findlay


3 Answers

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>
like image 158
hogan Avatar answered Oct 18 '22 22:10

hogan


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>
like image 27
Almund Avatar answered Oct 18 '22 22:10

Almund


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>
like image 45
Tengiz Avatar answered Oct 18 '22 20:10

Tengiz