Codementor Events

Guide to Building Reusable Components in Angular 2

Published Apr 25, 2017
Guide to Building Reusable Components in Angular 2

Disclaimer: Before we begin, for you to be able to follow this post, you must have some basic knowledge of Angular v2.x Framework.

This post wil use the Plunker website as an example. If Plunker doesn't have certain features that are described in the section, "Preparing the environment,", please find some other environment described in this article.

Table of Content

One of the biggest changes that we've seen as we moved from Angular v1.x to Angular v2 was its architecture. In the fist version, the library was an MVC, a Model View Controller architecture; in the second version, it became Component-based architecture, which is very similar to the MVC. One of the main ideas dehind the component-based architecture is that the components can be reused easily in any part of our application. You've probably already built many components and have reused them within your app.

Today I will try to show you how to build a really generic and reusable component in the Angular framework. The main focus of this article will be a content projection, which was called transclusion in Angular 1.

Preparing the Environment

For this post, I'm going to use Plunker online editor because it allows us to build examples in Angular 2.

To choose the correct environment,

  1. Go to the Plunker website
  2. Choose an option to open an editor
  3. Create a new Plunk by selecting Angular 2 as the predefined environment, like so:
    img1.PNG

After you've created a new plunk with Angular 2 default, you should have a working application. If you click on "Run" at the top of the page, you should see the working application results:
img2.PNG

Creating an Article Component

Let's create one more component, which is going to be our generic reusable component. As an example, I propose creating an article component with a header and a body of the article.

Click on "New File" in the menu on the left and enter: src/article/article.component.ts

Now, let's register our component inside the app module, which is located inside the src/app.ts file.

Create a structure of the article component — you can leave it blank for now:

import { Component } from '@angular/core'

@Component({
  selector: 'article',
  template: `
    <div>
      Hello from article component
    </div>
  `,
})
export class ArticleComponent {
  
  constructor() {
    
  }
}

Now, import your component into the app component and use it in the app component's template. In the end, it should look like this:

img3.PNG

Creating an Article

One of the options of creating the article was to have it inside our app component's template:

<div>
      <h2>Hello {{name}}</h2>
    </div>
    <article></article>
    <div>
      <h3>My Article</h3>
      <p>my article body</p>
</div>

Another option would be to extract this code from the app component and place it in the article component's template so it looks like this:

img4.PNG

But in that situation, our article component didn't look very reusable.

img5.PNG

We could pass the header and body in the input properties for the component, but if we want to structure each article body in different ways (applying different HTML to that), we may run into some problems.

Introducing <ng-content>

Here's where the content projection comes into play.

What makes content projection so powerful is its ability to change the content inside a component based on the needs of the application.

To use the content projection, we should go to our article component and use the <ng-content> tag, which is going to include the article contents that we may pass from the app component.

Make the follwing change in the article component:

@Component({
  selector: 'article',
  template: `
    <div>
      <h3>My Article</h3>
      <ng-content></ng-content>
    </div>
  `,
})
export class ArticleComponent {
  
  constructor() {
    
  }
}

And now, the following change in the app component:

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
    </div>
    <article>
      <p>my article body 1</p>
    </article>
    
    <br />
    <article><p>my article body 2</p></article>
  `,
})
export class App {
  name:string;
  constructor() {
    this.name = 'Angular2'
  }
}

So now, you can see the result. The content that we've defined inside our app component was projected into the article component:

img6.PNG

We still have a small problem with the header section of our article component. We could use an Input to pass text to the header, but there is another solution:

Multiple Projections

Actually, they're very easy to implement. What we need to do is to associate a property in each call for the component, and then give that property to the place where we want to project that piece of code.

First, let's go and change the code inside our article component. We will have several projections, which will look different from the attributes. The code should look like this:

@Component({
 selector: 'article',
 template: `
   <div>
     <ng-content select="[header]"></ng-content>
     <ng-content select="[body]"></ng-content>
   </div>
 `,
})
export class ArticleComponent {
 
 constructor() {
   
 }
}

And now, inside our app component, go ahead and make the following changes:

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>
    </div>
    <article>
      <h3 header>My Article 2</h3>
      <p body>my article body 1</p>
    </article>
    
    <br />
    <article>
      <h3 header>My Article 2</h3>
      <p body>my article body 2</p>
    </article>
  `,
})
export class App {
  name:string;
  constructor() {
    this.name = 'Angular2'
  }
}

If everything was performed correctly, you should see the following result:

img7.PNG

This way, we'll have truly reusable components, which you can project the content that you need for both header and footer, as well as create aditional sections of your component and make a projection there (i.e. footer section, etc.)

Here's a fully working plunk.

Final Remarks

In this article, we went through how to build a very specific kind of reusable component. Reusability is very important when you're programming, and anything we can do to reduce duplication of code is going to help us out. With content projection, we can create components whose reusable pieces are limited to just the external portions of the component, and the inner pieces could be different based on the needs of the application. This is content projection, and it is an important tool to have in our belt when developing applications with the Angular 2 framework.

Discover and read more posts from Anton Selin
get started
post commentsBe the first to share your opinion
Gali Lisson
5 years ago

I redeemed it! Great! Thank You

Алекс Бородулин
5 years ago

Hello, it’s bad article, because in real practice nested component need interact with parent container. Article don’t explain this case

Toby Johnson
7 years ago

Hello, looks like you’ve accidentally given both articles the same title “My Article 2” which makes the example a bit less useful :)

Show more replies