angular tutorials

How to access ng-content with @ContentChild – Angular Component ?

This tutorial guides you on how to access ng-content using @ContentChild decorator within Angular component in Angular application.

Access ng-content using @ContentChild – Angular Component

You had learnt in our previous tutorials on how to project contents into angular components using ng-content, were we could project content from parent component (App Component) in to the designated child component.

Also, learnt View Child and how to access in life cycle hooks  in another tutorial. In this tutorial you will learn how to decorate a parameter that will be used to configure content query i.e., it can be used to get the first element or the directive matching the selector from the content DOM.

Note, content queries are set before the ngAfterContentInit() callback is called.

For example, refer comment “Projecting content into component with ng-content“. I had placed the local reference “#contentParagraph” on the pragraph.

app.component.html

<div class="container">
  <app-create-item (itemAdded)="onItemAdded($event)"
                   (itemSpecAdded)="onItemSpecAdded($event)"></app-create-item>
  <hr>
  <div class="row">
    <div class="col-xs-12">
      <button class="btn btn-primary" (click)="onChangeComponentElement()">Change item element</button>
      <!-- To Demo ngOnDestroy() -->
      <button class="btn btn-danger" (click)="onDestroyComponentElement()"> Destroy component</button>
      <app-item-element *ngFor="let elem of itemElems"
                        [itemElem] = "elem"
                        [title] = "elem.title">
                        <!-- Projecting content into component with ng-content -->
                        <p #contentParagraph>
                          <strong *ngIf="elem.type === 'item'" style="color: orange">{{ elem.desc }}</strong>
                          <em *ngIf="elem.type === 'spec'">{{ elem.spec }}</em>
                        </p>
      </app-item-element>
                   
    </div>
  </div>
</div>

Once you project content into App Component using ng-content. Now, using the template reference variable “#contentParagraph” you can access ng-content using @ContentChild within Angular component (ItemElementComponent) class as shown below.

item-element.component.ts

import { 
  AfterViewChecked,
  AfterViewInit,
  AfterContentChecked,
  AfterContentInit,
  Component, 
  DoCheck, 
  Input, 
  OnChanges, 
  OnInit, 
  SimpleChanges,
  OnDestroy,
  ViewChild,
  ElementRef,
  ContentChild  
} from '@angular/core';

@Component({
  selector: 'app-item-element',
  templateUrl: './item-element.component.html',
  styleUrls: ['./item-element.component.css'],
})

export class ItemElementComponent implements OnInit, OnChanges, DoCheck, AfterContentInit, AfterContentChecked, AfterViewInit, AfterViewChecked, OnDestroy{

  @Input() itemElem : {type: string, title: string, desc: string, spec: string};
  @Input() title : string;
  @ViewChild('heading', {static: true}) header : ElementRef;
  @ContentChild('contentParagraph', {static: true}) paragraph : ElementRef;
  
  constructor() {
    console.log("constructor called.....");
  }

  ngOnChanges(changes: SimpleChanges) {
    console.log("ngOnChanges called.....");
    console.log(changes);
  }

  ngOnInit(): void {
    console.log("ngOnInit called.....");
    console.log('Header Content:' + this.header.nativeElement.textContent);
    console.log('Paragraph text Content:' + this.paragraph.nativeElement.textContent);
  }

  ngDoCheck(){
    console.log("ngDoCheck called.....");
  }

  ngAfterContentInit(){
    console.log("ngAfterContentInit called.....");
    console.log('Paragraph text Content:' + this.paragraph.nativeElement.textContent);
  }

  ngAfterContentChecked(){
    console.log("ngAfterContentChecked called.....");
  }

  ngAfterViewInit(){
    console.log("ngAfterViewInit called.....");
    console.log('Header Content::::::' + this.header.nativeElement.textContent);
  }

  ngAfterViewChecked(){
    console.log("ngAfterViewChecked called.....");
  }

  ngOnDestroy(){
    console.log("ngOnDestroy called.....");
  }

}

Note, you need to add {static: true} as a second argument, if you are planning to access the selected element inside of ngOnInit(). And if you don’t access the selected element in ngOnInit(), but elsewhere in your component the set {static: false} instead.

Also, note if you are using Angular 9+, you need to add {static:true}  if needed, but not {static:false}

Of course, you can’t access the value “paragraph” of before you reach ngAfterContentInit() as shown below***.

item-element.component.ts:43 constructor called.....
item-element.component.ts:47 ngOnChanges called.....
item-element.component.ts:48 {itemElem: SimpleChange, title: SimpleChange}
item-element.component.ts:52 ngOnInit called.....
***item-element.component.ts:53 Header Content:
***item-element.component.ts:54 Paragraph text Content:
item-element.component.ts:58 ngDoCheck called.....
item-element.component.ts:62 ngAfterContentInit called.....
***item-element.component.ts:63 Paragraph text Content:Android phone by Google

That’s it. You had learnt how to project contents into angular components using ng-content. Also, learnt how to access ng-content using @ContentChild decorator within Angular component.

Hope it helped 🙂

References:

Leave a Reply

avatar
  Subscribe  
Notify of