angular tutorials

Project contents into angular components using ng-content

This tutorial guides you on how to project contents into angular components using ng-content. You should know that content projection and ng-content is one of the helpful angular features to build reusable components. 

Project contents into angular components using ng-content

In the following example let’s learn how to project contents into angular components using ng-content. In this example, we are going to project content from parent component (App Component) in to the designated child component (ItemElementComponent).

For example, your child component’s template file have the following code.

<div
class="panel panel-default">
<div class="panel-heading">{{ itemElem.title }}</div>
<div class="panel-body">
  <p>
    <strong *ngIf="itemElem.type === 'item'" style="color: orange">{{ itemElem.desc }}</strong>
    <em *ngIf="itemElem.type === 'spec'">{{ itemElem.spec }}</em>
  </p>  
</div>
</div>

In the above code the following HTML code section may not look like complex. But if we have complex HTML code, then property binding may not be the best solution for passing data around. Because, Angular will escape HTML code to prevent Cross-site Scripting Attack. Therefore, ng-content is the way that you should use to display the below content.

  <p>
    <strong *ngIf="itemElem.type === 'item'" style="color: orange">{{ itemElem.desc }}</strong>
    <em *ngIf="itemElem.type === 'spec'">{{ itemElem.spec }}</em>
  </p>

Note, in our ItemElementComponent template code we are checking type ‘item’ or ‘spec’ (HTML code). And sometimes the HTML code may have complex logic which you wanted to pass into component from outside. Let’s see how to pass the data in next section.

And let’s say the child component’s class code look like below.

import { Component, Input, OnInit, ViewEncapsulation } from '@angular/core';

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

export class ItemElementComponent implements OnInit {

  @Input() itemElem : {type: string, title: string, desc: string, spec: string};
  
  constructor() { }

  ngOnInit(): void {
  }

}

Then let’s say your App Component’s template and class file looks like below

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">
      <app-item-element *ngFor="let elem of itemElems"
                        [itemElem] = "elem">                        
      </app-item-element>                        

    </div>
  </div>
</div>

app.component.ts

import { Component } from '@angular/core';

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

export class AppComponent {
  itemElems = [{type: 'item', title:'Google Pixel', desc:'Android phone by Google', spec:''},
  {type: 'spec', title:'Specifications', desc:'', spec:"Specifications of Google Pixel"}];

  onItemAdded(itemData:{itemTitle: string, itemDesc: string}) {
    this.itemElems.push({
      type: 'item',
      title: itemData.itemTitle,
      desc: itemData.itemDesc,
      spec:''
    });
  }

  onItemSpecAdded(itemSpecData:{itemTitle: string, itemSpec: string}) {
    this.itemElems.push({
      type: 'spec',    
      title: 'Specifications',
      desc:'',    
      spec: 'Specifications of '+ itemSpecData.itemTitle
    });
  }
  
}

Angular access ng-content within child component

Let’s see how to modify the above example to access ng-content within child component i.e., how to pass or project content from parent component to child component.

What you need to do is to replace that HTML code in the child component with placeholder tag for the content i.e., <ng-content> tags as shown below. I had just commented the HTML code section as you see below and added <ng-content> tags.

<div
class="panel panel-default">
<div class="panel-heading">{{ itemElem.title }}</div>
<div class="panel-body">

  <!-- Projecting content into component with ng-content-->
  <ng-content> </ng-content>
  <!--   <p>
    <strong *ngIf="itemElem.type === 'item'" style="color: orange">{{ itemElem.desc }}</strong>
    <em *ngIf="itemElem.type === 'spec'">{{ itemElem.spec }}</em>
  </p>   -->
  
</div>
</div>

Note, think of this like a String Interpolation feature, but on a bigger scale and the value for <ng-content> </ng-content> comes from the component in its execution context.

Further, you need to make the following changes to your parent component (App Component) template file.

<div class="container">
  <app-create-item (itemAdded)="onItemAdded($event)"
                   (itemSpecAdded)="onItemSpecAdded($event)"></app-create-item>
  <hr>
  <div class="row">
    <div class="col-xs-12">
      <app-item-element *ngFor="let elem of itemElems"
                        [itemElem] = "elem">
                        <!-- Projecting content into component with ng-content -->
                        <p>
                          <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>

What we have done is, we had replaced HTML code with <ng-content> tags in the child component and placed/added the same logic inside the app component’s template as shown above i.e., pasted HTML code inside opening and closing tag of your own component <app-item-element></app-item-element>.

That’s it. Now you had learnt how to access the ng-content within child component. Hope it helped 🙂

Also See:

References:

guest
0 Comments
Inline Feedbacks
View all comments