Introduction
In this article, we will be looking into how to create a nested component using Angular 2 framework and pass data from parent component to the child component. Before reading this article, I would recommend reading two of my prior articles for better understanding. This article refers to source code available in a previous article available here.
I would like to get feedback on this article. Please feel free to share your comments below. If you like this article, please don't forget to rate it.
Prerequisites
- Angular 2 development environment already setup (for reference, click here)
- Basic running Angular 2 App (for reference, click here)
Let's Get Started
Let's get started, copy the previous article source code (available here) to new folder nestedComponent. Inside nestedComponent folder, we need to re-install npm packages using npm install
. This is how your folder should look like after npm install
.
In this article, we will move label which was getting rendered at the bottom of student-form
component to nested component. This is how our student-form.html will look like after labels are removed.
<div>
Student First Name :- <input [(ngModel)] = "Student.FirstName" type="text"><br/>
Student Last Name :- <input [(ngModel)] = "Student.LastName" type="text"><br/>
Student Age :- <input [(ngModel)] = "Student.Age" type="text"><br/>
</div>
Now let's add a new file in app folder and name it student-detail.component.ts. This file will have logic for the student-detail
component.
import { Component, Input } from '@angular/core';
@Component({
selector: 'student-detail',
templateUrl: '../view/student-detail.html'
})
export class StudentDetailComponent {
@Input() FirstName:String;
@Input() LastName:String;
@Input() Age:number;
}
In this component, we will be passing data from parent control to be rendered. To achieve this, we will also import Input from angular/core. We have defined selector
and templateUrl
at line 4 & 5. To map parent input with Student-Detail component, we have defined @input()
and defined FirstName
, LastName
& Age
at line 9, 10 & 11.
We can also have variable name and attribute name different. To have different attribute name, name needs to be defined inside bracket for example @Input('first-name')
import { Component, Input } from '@angular/core';
@Component({
selector: 'student-detail',
templateUrl: '../view/student-detail.html'
})
export class StudentDetailComponent {
@Input('first-name') FirstName:String;
@Input('last-name') LastName:String;
@Input() Age:number;
}
Similarly, we can also evolve methods from parent control using Output. To achieve this, we will have to inject Output
& EventEmitter
dependency and then add a method to evoke parent
method.
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'student-detail',
templateUrl: '../view/student-detail.html'
})
export class StudentDetailComponent {
@Input('first-name') FirstName:String;
@Input('last-name') LastName:String;
@Input() Age:number;
@Output('onButtonClick') buttonClick = new EventEmitter();
onCLick(){
this.buttonClick.emit();
}
}
Now we need to add HTML file we referred at line 5. Add this file inside view folder and name it student-detail.html.
<section>
<br/>
<div>Student Details are ...</div>
<div>
First Name : {{FirstName}} <br/>
Last Name : {{LastName}} <br/>
Age : {{Age}}
</div>
<button (click)="onCLick()">Click Me</button>
<br/>
<ng-content></ng-content>
</section>
In the HTML template we just added, we are referring to variable defined in student-detail.component.ts at line 5,6 & 7. I have highlighted this variable name in the above HTML template. At line 7, we have mapped onClick
method which will internally evoke parent
control method mapped to it.
In the HTML template, we have also added ng-content
tag. This tag will be rendering content we place between student-detail
tag. We will discuss this more when we add student-detail
tag in our main component student-form
. Let's start injecting our new created component in student-form
. Here is the updated template with student-detail
tag.
<div>
Student First Name :- <input [(ngModel)]="Student.FirstName" type="text"><br/>
Student Last Name :- <input [(ngModel)]="Student.LastName" type="text"><br/>
Student Age :- <input [(ngModel)]="Student.Age" type="text"><br/>
<student-detail first-name="{{Student.FirstName}}" last-name="{{Student.LastName}}"
Age="{{Student.Age}}" (onButtonClick)="onButtonClick()">
<div>This is inside nested control</div>
</student-detail>
</div>
At line 5 & 6, we have added tag student-detail
attributes, FirstName
LastName
& Age
with respective parent variable mapping. onButtonClick()
method is mapped to child control. We have used the curly bracket for mapping variable but the same can also be achieved using square bracket as mentioned below:
<student-detail [first-name]="Student.FirstName" [last-name]="Student.LastName"
[Age]="Student.Age" (onButtonClick)="onButtonClick()">
<div>This is inside nested control</div>
</student-detail>
Now we need to add onButtonClick
method to student.component.ts.
import { Component } from '@angular/core';
import { StudentModel } from './student.model'
@Component({
selector: 'student-form',
templateUrl: '../view/student-form.html'
})
export class StudentComponent {
Student : StudentModel = new StudentModel();
onButtonClick = function(){
alert('Hey, button was clicked in child control');
}
}
If you have noticed div
tag between student-detail
tag, the same will be passed to student-detail
component and will be rendered inside ng-content
tag which we have added inside student-detail
component. If you have worked with Angular 1.x, this is similar to ng-transclude
.
The final step is to map dependency in student.module.ts. Below is updated student.module.ts and I have highlighted changes made to this file.
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { StudentComponent } from './student.component';
import {StudentDetailComponent} from './student-detail.component';
import {FormsModule} from '@angular/forms';
@NgModule({
imports: [ BrowserModule, FormsModule],
declarations: [ StudentComponent, StudentDetailComponent ],
bootstrap: [ StudentComponent ]
})
export class AppModule { }
At line 4, studentDetailComponent
has been imported and at line 9, we mapped the same object in declarations. This is how your final folder should look like:
Now open a command prompt and navigate to base folder & execute npm start
. You should now see final out in your default browser. If you type inside textbox, the same should get displayed inside nested component.
Summary
In this article, we created a nested component which takes data from parent component and then renders it. We did also look into a couple of ways we can map data with child control.
Reference