ContentChild And ContentChildren In Angular

ContentChild And ContentChildren In Angular

We use the ContentChild and ContentChildren decorators to Query and obtain the reference to the Projected Content in the DOM. The content this component receives from a parent component is known as projected content.

The ViewChild & ViewChildren are extremely similar to the ContentChild & ContentChildren. To Query and obtain the reference of any DOM element in the Component, we use the ViewChild or ViewChildren. A DOM element can be an HTML element, a Child Component, a directive, or something else entirely. However, we can't access the reference to the template added with the Content projection using ViewChild or ViewChildren.

Content Projection

The HTML content is passed from the parent component to the child component using content projection. The template will be shown in a specific location by the child component. The ng-content element is used to identify a location for the template in the child component's template. The selector attribute in ng-content also allows us to construct several slots. Each of the slots can receive distinct material from the parent.

ContentChild and ContentChildren Example

Let's make a basic card application to see how ContentChild and ContentChildren function. A CardComponent is included in the application, which shows a single Card.

import { Component} from '@angular/core';
 
 
@Component({
  selector: 'card',
  template: `
 
    <div class="card">
      <ng-content select="header"></ng-content>
      <ng-content select="content"></ng-content>
      <ng-content select="footer"></ng-content>
    </div> 
   
  `,
  styles: [
    ` .card { min- width: 280px;  margin: 5px;  float:left  } 
    `
  ]
})
export class CardComponent {
 
}

Three ng-content slots are defined by the component. Header, content, and footer are the names of the slots. Content can be sent to any or all of these three slots by users of the card component.

The Card List Component provides the following code.

Three Card Components are created by the Card List Component. Sends header, content, and footer material.

Also, on the h1 element in the header text, we have a #header template reference variable. Let's use the ContentChild query in the Card Component to get to the h1 element.

import { Component } from '@angular/core';
 
@Component({
  selector: 'card-list',
  template: `
  
  <h1> Card List</h1>
 
      <card>
        <header><h1 #header>Angular</h1></header>
        <content>One framework. Mobile & desktop.</content>
        <footer><b>Super-powered by Google </b></footer>
      </card>
        
      <card>
        <header><h1 #header style="color:red;">React</h1></header>
        <content>A JavaScript library for building user interfaces</content>
        <footer><b>Facebook Open Source </b></footer>
      </card>
 
      <card>
        <header> <h1 #header>Typescript</h1> </header>
        <content><a href="https://www.tekarticleshub.com/typescript-article/"> Typescript</a> is a javascript for any scale</content>
        <footer><i>Microsoft </i></footer>
      </card>
 
  `,
})
export class CardListComponent {
 
}

Using ContentChild and ContentChildren

Let's return to the Card Component now.

To use ContentChild, we must first import it from the @angular/core package.

import { Component, ContentChild, ContentChildren, ElementRef, Renderer2,  ViewChild } from '@angular/core';

Then query the header from the projected content with it.

@ContentChild("header") cardContentHeader: ElementRef;

The variable is cardContentHeader in this case. On that variable, we use the @ContentChild decorator. We want to read the header, which is a template variable. It will return the ElementRef because it is applied to the h1 tag.

The cardContentHeader will not be accessible right away. Component lifecycle hooks, for example. The component is first initialized by the angular. The ngOnChanges, ngOnInit, and ngDoCheck hooks are then raised. Following that, the projected components are initialized. The AfterContentInit and AfterContentChecked hooks are then raised by Angular. As a result, the cardContentHeader is only available after the AfterContentInit hook.

We can use the renderor2 to alter the DOM Element's styles and other properties once we have a reference to it.

ngAfterContentInit() {
   
    this.renderor.setStyle(this.cardContentHeader.nativeElement,"font-size","20px")
 
}

ViewChild Vs ContentChild

Any DOM element, component, or directive can be accessed using ViewChild or ViewChildren. It cannot, however, be used to view the projected content. While ContentChild or ContentChildren can only view the projected content, they can't access anything else.

Use the ViewChild query to read the header element in the card component, for example. The cardViewHeader will be undefined, as you will notice.

ContentChild Syntax

The ContentChild query retrieves the first matching element from the DOM and modifies the component variable we're using it on.

Syntax

The ContentChild has the following syntax.

ContentChild(selector: string | Function | Type<any>, opts: { read?: any; static: boolean; }): any

On a Component Property, we use the contentChild decorator. There are two arguments required. A selector and opts.

selector (Query Selector): The querying directive's type or name.

opts: has two possibilities.

static: True if you want to resolve query results before change detection, false if you want to resolve query results after change detection. The default value is false.

read: This method is used to read the various tokens from the queried elements.

Selector or Query Selector

The change detector searches for the first element that fits the selector and adds the element's reference to the component property. The change detector updates the component property when the DOM changes and a new element meets the selector.

A string, a type, or a function that returns a string or type can be used as the query selector. The selections listed below are supported.
  • Any form of a component or directive class
  • Like a string, a template reference variable
//Using a Template Reference Variable
@ContentChild("header") cardContentHeader: ElementRef;

//Using component/directive as type @ContentChild(childComponent) cardChildComponent: childComponent;

Static

When the query is resolved, this value is set. True when the view is created for the first time (before the first change detection). If you want it to be resolved after each change detection, set False.

Read Token

It can be used to read the various tokens from the queried items.

Consider the following example of projected material. The title An input element or a ngModel directive can be used as input.

<input #nameInput [(ngModel)]="name">

The input element is returned as elementRef  by the ContentChild in the following code.
@ContentChild('nameInput',{static:false}) nameVar;

The read token can be used to ask ContentChild to return the right type.

Read this as an example: The name is returned by NgModel. Type-specific input NgModel

@ContentChild('nameInput',{static:false, read: NgModel}) nameVarAsNgModel;
@ContentChild('nameInput',{static:false, read: ElementRef}) nameVarAsElementRef;
@ContentChild('nameInput', {static:false, read: ViewContainerRef }) nameVarAsViewContainerRef;

ContentChildren

To get a list of element references from the projected content, use the ContentChildren decorator.

ContentChildren is not the same as ContentChild.

ContentChild always returns a single element reference. When there are many elements, ContentChild returns the first one that matches.

ContentChildren always returns a QueryList with all the matching components. You can access each entry by iterating over the list.

Syntax

The contentChildren has the following syntax. Its syntax is extremely similar to that of contentChild. It doesn't have the static option, but it does have descendants.

ContentChildren(selector: string | Function | Type<any>, opts: {descendants?:boolean, read?: any; }): any

Produce descendants If true, all descendants are included; otherwise, only direct children are included.

After the change detection, the ContentChildren is always resolved. That is, why isn't there a static option? You also can't use it in the ngOnInit hook because it hasn't been initialized yet.

Conclusion

In this article, we covered what is ContentChild And ContentChildren and how to use them in Angular applications.

I hope this article helps you and you will like it.👍

If you have any doubt or confusion then free to ask in the comment section.

Post a Comment

Previous Post Next Post