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
- Preparing the Environment
- Creating an Article Component
- Creating an Article
- Introducing <ng-content>
- Multiple Projections
- Final Remarks
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,
- Go to the Plunker website
- Choose an option to open an editor
- Create a new Plunk by selecting Angular 2 as the predefined environment, like so:
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:
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:
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:
But in that situation, our article component didn't look very reusable.
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:
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:
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.
I redeemed it! Great! Thank You
Hello, it’s bad article, because in real practice nested component need interact with parent container. Article don’t explain this case
Hello, looks like you’ve accidentally given both articles the same title “My Article 2” which makes the example a bit less useful :)