Angular Content Projection using <ng-content>

Angular provides lots of features, and one of the most important feature is component reusability. To reuse the components we can use content projection or ng-content. Let’s understand how we can use <ng-content> to reuse the component and project the contents dynamically.

Let’s take a simple example. Suppose we have two forms as following:

We want this one to be a ‘Create User’ form & the other one to be a ‘Login’ form. And we just need a different form title and the button text for each of the forms with the same fields i.e ‘Email Address’ & ‘Password’. So it’s not a good practice to create two separate forms/components. Then using a single form/component how can we solve this problem ?

Here we can use content projection to change a piece of form. Let’s see how we can do this ? Look at the code below:

<auth-form (submitted)=”createUser($event)”></auth-form><auth-form (submitted)=”loginUser($event)”></auth-form>

For both Login and Create Account forms we are using the same selector of AuthFormComponent. If we look at the template code:

<form #form=”ngForm” (ngSubmit)=”onSubmit(form.value)”>
<h3>My Form</h3>

<div class=”form-group”>
<label for=”email”>Email Address:</label>
<input type=”text” class=”form-control” id=”email”>
</div>
<div class=”form-group”>
<label for=”password”>Password:</label>
<input type=”password” class=”form-control” id=”pwd”>
</div>
<button mat-button color=”success”>Save</button>
</form>

Using this code it will render the forms the same as above images. Now we want the title to be ‘Create Account’ for one form and ‘Login’ to another instead ‘My Form’. So this is where the content projection is useful. We need to pass pieces of information in between these component tags, like this:

<auth-form (submitted)="createUser($event)">
<h3>Create Account</h3>
</auth-form>
<auth-form (submitted)="loginUser($event)">
<h3>Login</h3>
</auth-form>

But if we do only this much part it’s not going to work. So what we need to actually do is, project the content through something called as ng-content. We need to replace form title which we are showing using <h3> tag in auth component with <ng-content> like this:

<form #form=”ngForm” (ngSubmit)=”onSubmit(form.value)”>
<ng-content></ng-content>

<div class=”form-group”>
<label for=”email”>Email Address:</label>
<input type=”text” class=”form-control” id=”email”>
</div>
<div class=”form-group”>
<label for=”password”>Password:</label>
<input type=”password” class=”form-control” id=”pwd”>
</div>
<button mat-button color=”success”>Save</button>
</form>

In the browser’s console we can see that the content has been projected inside our forms. See the below image for reference.

Ok! Now what if we have multiple contents to project dynamically within a single form?

Projection slots with ng-content

Now our next use case is we want to inject different buttons based on form. For example, we want button text as ‘Sign Up Free’ for create account form & ‘Login’ for login form instead of ‘Save’.

To do this we need to add a button like we did to show dynamic form title:

<auth-form (submitted)="createUser($event)">
<h3>Create Account</h3>
<button type="submit">Sign Up Free</button>
</auth-form>
<auth-form (submitted)="loginUser($event)">
<h3>Login</h3>
<button type="submit">Login</button>
</auth-form>

After doing above changes our forms look like:

Oops! Here we have dynamic buttons as per our need but the placement of buttons are wrong. How can we fix this issue ? So the answer is using content projection slots. It tells us where to inject each particular piece of information.

Let’s see how we can do this. First we will remove the extra button ‘Save’ which we can see at the bottom & this is from our common auth component. And instead at that place we can add another ng-content tag to display our buttons at the bottom. Now the way to know which ng-content is for which selector is, using a ‘select’ attribute. Syntax for this is, select=“<tag_name>”.

Check the code below how we can do this:

<form #form=”ngForm” (ngSubmit)=”onSubmit(form.value)”>
<ng-content select=”h3"></ng-content>
<div class=”form-group” style=”padding-top: 20px;”>
<label style=”font-weight: 500;” for=”alterEgo”>Email Address:</label>
<input type=”text” class=”form-control” id=”alterEgo”>
</div>
<div class=”form-group”>
<label style=”font-weight: 500;” for=”alterEgo”>Password:</label>
<input type=”text” class=”form-control” id=”alterEgo”>
</div>
<ng-content select=”button”></ng-content>
</form>

And doing above changes our forms look like this:

This works similar to a document query selector. Instead of tag-name to select, we can also pass CSS class or id name like this: select=“.class_name” or select=“#id_name”.

Note: <ng-content> does not produce a content, it simply projects existing content.

I hope you enjoyed this article. If you have any queries, you can ask me in the comments section below. Thank You !

--

--

--

JS | Angular | React | PWA

Recommended from Medium

Solving the first three SICP problems with Airscript

Optimize your JS code using Google's V8 internals

Finding prime numbers by threads in java(1)

React Notes

JavaScript Some Awesome Features.

How to solve Cannot find module ‘fs/promises’?

Good bye Nuxt 2, hello Nuxt 3

Quick View: AMPScript and Marketing Cloud

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Anjali Tanpure

Anjali Tanpure

JS | Angular | React | PWA

More from Medium

Angular Google Social Login and AuthGuard

Introduction to Angular Directives

How to Creating Angular Project using Angular CLI Command?.

Explain Container and Nested Components in Angular

Explain Container and Nested Components in Angular