Simplifying Content Projection in Angular

Dhananjay Kumar / Tuesday, September 5, 2017

In Angular, content projection is used to project content in a component. Let’s take a closer look at how it works:

Content projection allows you to insert a shadow DOM in your component. To put it simply, if you want to insert HTML elements or other components in a component, then you do that using concept of content projection. In Angular, you achieve content projection using < ng-content >< /ng-content >.  You can make reusable components and scalable application by right use of content projection.

 To understand content projection, let us consider GreetComponent as shown in the code listing below: 

import { Component } from '@angular/core';
 
@Component({
    selector: 'greet',
    template: `{{message}}`
})
export class GreetComponent {
 
    message: string = "Hello There !"
 
}

Now if you use GreetComponent in another component, and want to pass a greeting message from the parent component, then you should use the @Input() decorator. This way, a modified GreetComponnet will look like the listing below:

import { Component, Input } from '@angular/core';
 
@Component({
    selector: 'greet',
    template: `{{message}}`
})
export class GreetComponent {
 
    @Input() message: string;
 
}

Using the @Input() decorator, you can pass a simple string to the GreetComponnet, but what if you need to pass different types of data to the GreetComponent such as:

  1. Inner HTML
  2. HTML Elements
  3. Styled HTML
  4. Another Component etc.

To pass or project styled HTML or another component, content projection is used. Let us modify the GreetComponent to use content projection in this code: 

We are using to project content in the GreetComponent. When you use the GreetComponent, you’ll pass content as shown below:

In the listing above, you are projecting styled HTML to the GreetComponent and you’ll get the following output:

This is an example of Single Slot Content Projection. Whatever you pass to the GreetComponent will be projected. So, let us pass more than one HTML element to the GreetComponent as shown in the listing below:

Here we are passing three HTML elements to the GreetComponent, and all of them will be projected. You will get the output as shown in the image below:

In the DOM, you can see that inside the GreetComponent, all HTML elements are projected. 

Multi Slot Projection

 You may have a requirement to project elements in multiple slots of the component. In this next example, let’s say you want to create a greeting card like this:

This can be created using the component as shown below:

Let us say we have a requirement to pass the header element and a btn element so the name and button can be dynamically passed to the GreetComponent.  This time, we need two slots:

  1. A slot for the header element
  2. A slot for the btn element

Let’s modify the GreetComponent to cater to the above requirement as shown in the image below:

Here we’re using  ng-content two times. Now, the question is do we select a particular ng-content to project the  h1 element and another ng-content to project a btn  element?

You can select a particular slot for projection using the  ng-content> selector.  There are four types of selectors:

  1. Project using tag selector
  2. Project using class selector
  3. Project using id selector
  4. Project using attribute selector 

You can use the tag selector for multi slot projection as shown in the listing below:

Next, you can project content to the GreetComponent as shown in the listing below:

As you can see, we are using the GreetComponent twice and projecting different h1 and button elements. You’ll get the output as shown in the image below:

The problem with using tag selectors is that all h1 elements will get projected to the GreetComponent. In many scenarios, you may not want that and can use other selectors such as a class selector or an attribute selector, as shown in the listing below:

Next, you can project content to the GreetComponent as shown in the listing below:

You’ll get the same output as above, however this time you are using the class name and attribute to project the content. When you inspect an element on the DOM, you will find the attribute name and the class name of the projected element as shown in the image below: 

 

Content projection is very useful to insert shadow DOM in your components. To insert HTML elements or other components in a component, you need to use content projection. In AngularJS 1.X, content projection was achieved using Transclusion, however in Angular it is achieved using <ng-content>

In the next post, you will learn about more important concepts in Angular, so stay tuned. Also, do not forget to check out Ignite UI for JavaScript/HTML5 and ASP.NET MVC, which you can use with HTML5, Angular, React, and ASP.NET MVC to create rich Internet applications. You can download a trial of all our JavaScript controls for free!