Content Projection
Sep 07 2018 06:17pm | | Share

Angular – Content Projection: Creating a Notification Component

By Michael Vano

With the growing complexity of websites becoming closer to full blown applications, it is becoming more and more difficult to keep consistent style and structure throughout a project.

In this blog post, we will be looking at Content Projection in Angular; a feature that will help reduce some complexity and duplication of code in your project.

 

What it is and its Purpose

Content Projection is a way of templating content in an Angular project so that you can create a re-usable component throughout your website.

At the same time, it allows for flexibility in the content you wish to pass into the component. It is up to you how you wish to utilize it.

For this post, we will create a Notification Component that will utilize the features of Content Projection, and we will see how useful this feature can be in a project.

A notification is something that has dynamic content and is used for relaying various types of information to a user. It is a good example of how powerful Content Projection can be.

Before starting, please take note that this example will be using the SASS and Font Awesome libraries for Angular.

 

Creating the notification component

Let’s start off by creating the typescript file.


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

 @Component({

  selector: 'notification',

  templateUrl: './notification.component.html',

  styleUrls: ['./notification.component.scss']

})

export class NotificationComponent {

  @Input() type: "info" | "warning" | "error" | "success" = "info";

  @Input() title: string = "Notification Title";

}

You will notice that we have the input decorators for the notification “type” and “title”.

The “type” input variable can only be a string value of “info”, “warning”, “error” or “success”, with the default value being “info”.

We also have the “title” input variable, so that we can pass in a string to be displayed as the title/heading of the notification.

Next, let’s set up the HTML for our Notification Component.


<div class="notification-container {{type}}">

    <div class="heading">

        <div class="title">

            <div class="icon">

                <i *ngIf="type === 'info'" class="fas fa-info-circle"></i>

                <i *ngIf="type === 'warning'" class="fas fa-exclamation-triangle"></i>

                <i *ngIf="type === 'error'" class="fas fa-exclamation-circle"></i>

                <i *ngIf="type === 'success'" class="fas fa-check-circle"></i>

            </div>

            <div>

                {{ title }}

            </div>

        </div>

    </div>

    <div class="body">

        <ng-content></ng-content>

    </div>

</div>

Few things to take note of here. We have the “type” variable being used in the class to help style the notification accordingly and also using it to determine which icon to use.

We have the “title” variable being placed beside the icon in the heading area.

The most important thing to notice is the “ng-content” tag. This is where the dynamic content of the component will be placed. Later, we will get into more detail about this.

And last, but not least, let’s get some styling in there to make it look somewhat decent.


.notification-container {

    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;

    min-width: 20rem;

    max-width: 30rem;

    border-radius: 0.1875rem;

    background-color: #efefef;

    border: 0.125rem solid #999;

    &.info {

        border-color: #00aaff;

        .heading {

            background-color: #00aaff;

        }

    }

    &.warning {

        border-color: #e3e418;

        .heading {

            color: #333;

            background-color: #e3e418;

            i {

                color: #333;

            }

        }

    }

    &.error  {

        border-color: #b30101;

        .heading {

            background-color: #b30101;

        }

    }

    &.success {

        border-color: #30c530;

        .heading { background-color: #30c530; }

    }

    i { color: white; }

    .heading {

        color: white;

        display: flex;

        flex-direction: row;

        justify-content: space-between;

        align-items: start;

        padding: 0.5rem;

        .title {

            display: flex;

            justify-content: start;

            align-items: start;

            flex-direction: row;

            line-height: 1;

            .icon {

                margin-right: 0.5rem;

                margin-top: 0.1275rem;

            }

        }

    }

    .body { padding: 1rem 0.5rem; }

}

We have the scss file setup to co-ordinate with the notification types, so when the Notification Component uses the type “success”, it will have a green coloured theme to it. Each "type" will have its own colour palette.

Now that we have the component set up, let’s use it.

 

Using the Component

We can now use the notification component wherever we want. In this example, let’s just throw it into the app.component.html file.


<notification type="success" title="Something Successful Happened">

    Congratulations! You've created a component that uses Content Projection!

</notification>

Now to use the component in HTML, you call it in a tag by the selector you set in the typescript file. In this example, we set the selector as “notification”. Doing <notification></notification> will tell Angular to use render the “NotificationComponent” in this part of the HTML.

All the HTML in the Notification Component will be rendered at the position where the <notification></notification> tags are.

The cool part here is that anything in between the <notification> tags will be placed where we set the <ng-content> tag inside the notification component.

If we look at this code in the notification.component.html file.


<div class="body">

    <ng-content></ng-content>

</div>

The text, “Congratulations! You've created a component that uses Content Projection!” will be used and be rendered in place of the <ng-content></ng-content> tags, so it ends up rendering into something like:


<div class="body">

    Congratulations! You've created a component that uses Content Projection!

</div>

Putting it all together should look something like this.

Content Projection Message 1

Now you can put whatever you want between the <notification> tags and it will get rendered in the body of the notification. More div tags, a list, links another component; whatever you want.

Here is some code utilizing all the other types in notifications.


<p></p>

<notification type="info" title="Information">

    Information about how to create Re-usable components

</notification>

<p></p>

<notification type="warning" title="Warning!">

    Something happened. It's not too bad, but you should be aware of it.

</notification>

<p></p>

<notification type="error" title="Error Processing!">

    There was an error that occurred and you may have to deal with it. <br />

    <a href="http://google.com" target="_blank">Have a look at Google to find a solution.</a>

</notification>

This should look something like this:

Content Projection Message 2

Now we have a flexible re-usable Notification Component where we can easily customize the title and the content.