Angular Components: A Comprehensive Guide with Simple Examples on 2024
Angular Components serve as the fundamental elements within the Angular framework, enabling developers to craft dynamic and adaptable web applications. At the heart of Angular lie these Components, acting as the cornerstone of any Angular project. Throughout this guide, we delve deeply into the realm of Angular Components, elucidating their attributes, variations, and methods of interaction between disparate components. Through lucid examples, we aim to empower you to grasp the intricacies of Angular Components, leveraging their versatility to its utmost in your endeavors.
Understanding Angular Components
Any Angular application’s foundation is made up of Angular components. They are reusable components that provide functionality and style related to a section of the user interface. Building scalable and successful apps requires an understanding of how to design, manage, and use Angular components. We’ll get more into the lifetime of Angular components, their anatomy, and recommended practices for Angular Components based architecture in this part.
Anatomy of an Angular Component
Several essential components make to an angular component:
- Component Class: The TypeScript class defining the behavior of the component.
- Decorator: The @Component decorator, which offers the component’s selector, template, and styles, among other metadata.
- Template: The HTML that specifies the component’s view.
- Styles: CSS that specifies how a component looks.
- Metadata: Data that links a class to its template and styling and is supplied by the @Component decorator.
Creating an Angular Component
To create an Angular component, you can use the Angular CLI command:
ng generate component example
This command generates the following files:
example.component.ts
: The TypeScript file containing the component class.example.component.html
: The HTML template file.example.component.css
: The CSS file for styles.example.component.spec.ts
: The test file for the component.
Example: Basic Angular Component
Let’s start with a simple example of an Angular component.
Step 1: Creating the Component
First, generate the component using the Angular CLI:
ng generate component greeting
This command will create a folder named greeting
with the necessary files.
Step 2: Defining the Component Class
Open the greeting.component.ts
file and define the component class:
import { Component } from '@angular/core';
@Component({
selector: 'app-greeting',
templateUrl: './greeting.component.html',
styleUrls: ['./greeting.component.css']
})
export class GreetingComponent {
message: string = 'Hello, Angular!';
updateMessage() {
this.message = 'Welcome to the Angular world!';
}
}
In this example, we define a property message
and a method updateMessage
to change the message.
Step 3: Creating the Template
Open the greeting.component.html
file and add the following HTML:
<div>
<h1>{{ message }}</h1>
<button (click)="updateMessage()">Click Me</button>
</div>
This template displays the message
property and includes a button to trigger the updateMessage
method.
Step 4: Adding Styles
Open the greeting.component.css
file and add some basic styles:
div {
text-align: center;
margin-top: 50px;
}
button {
padding: 10px 20px;
font-size: 16px;
}
Result
When you run your Angular application, you should see the message “Hello, Angular!” and a button. Clicking the button changes the message to “Welcome to the Angular world!”.
Lifecycle of an Angular Component
From construction to destruction, there are several stages in the lifespan of an angular component. Angular has lifecycle hooks so you may access these phases. The lifecycle hooks that are most often utilized are:
- One call to ngOnInit() follows the initial ngOnChanges(). Initializing data there is a smart idea.
- ngOnChanges(): Whenever one or more data-bound input properties change, this lifecycle hook is called before any other.
- ngDoCheck(): Sounded immediately following ngOnChanges() and ngOnInit() in each change detection run.
- ngAfterContentInit(): Issued one time following the initial ngDoCheck() call.
- ngAfterContentChecked(): This function is called following each ngDoCheck() and ngAfterContentInit().
- One call to ngAfterViewInit() follows the initial ngAfterContentChecked().
- ngAfterViewChecked(): This function is called following each consecutive ngAfterContentChecked() and ngAfterViewInit().
- ngOnDestroy(): This function is called just before the component is destroyed by Angular.
Example: Lifecycle Hooks
import { Component, OnInit, OnDestroy, AfterViewInit } from '@angular/core';
@Component({
selector: 'app-lifecycle-demo',
template: '<p>Lifecycle Demo</p>',
styleUrls: ['./lifecycle-demo.component.css']
})
export class LifecycleDemoComponent implements OnInit, AfterViewInit, OnDestroy {
constructor() {
console.log('Constructor called');
}
ngOnInit(): void {
console.log('ngOnInit called');
}
ngAfterViewInit(): void {
console.log('ngAfterViewInit called');
}
ngOnDestroy(): void {
console.log('ngOnDestroy called');
}
}
Deep Dive into Angular Component Properties
Angular components come with a set of properties that enhance their functionality. These properties include inputs, outputs, lifecycle hooks, and more.
Inputs and Outputs
Inputs and outputs are used for communication between components. Inputs allow parent components to pass data to child components, while outputs allow child components to emit events to parent components.
Example: Using Inputs and Outputs
Let’s create a new component to demonstrate inputs and outputs.
ng generate component child
Child Component (child.component.ts
)
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent {
@Input() childMessage: string;
@Output() messageEvent = new EventEmitter<string>();
sendMessage() {
this.messageEvent.emit('Hello from Child Component!');
}
}
The @Input
decorator allows the parent component to pass data to the childMessage
property. The @Output
decorator, along with the EventEmitter
, allows the child component to send data to the parent component.
Child Component Template (child.component.html
)
<div>
<p>{{ childMessage }}</p>
<button (click)="sendMessage()">Send Message</button>
</div>
Parent Component (app.component.ts
)
import { Component } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
parentMessage = 'Message from Parent Component';
childMessage = '';
receiveMessage($event: string) {
this.childMessage = $event;
}
}
Parent Component Template (app.component.html
)
<div>
<app-child [childMessage]="parentMessage" (messageEvent)="receiveMessage($event)"></app-child>
<p>{{ childMessage }}</p>
</div>
Lifecycle Hooks
Lifecycle hooks allow you to tap into key events during the lifecycle of a component, such as when it is created, rendered, and destroyed.
Example: Using Lifecycle Hooks
import { Component, OnInit, OnDestroy } from '@angular/core';
@Component({
selector: 'app-lifecycle',
templateUrl: './lifecycle.component.html',
styleUrls: ['./lifecycle.component.css']
})
export class LifecycleComponent implements OnInit, OnDestroy {
constructor() {
console.log('Constructor called');
}
ngOnInit(): void {
console.log('ngOnInit called');
}
ngOnDestroy(): void {
console.log('ngOnDestroy called');
}
}
When you navigate to this component, you will see logs in the console indicating the different lifecycle stages.
Types of Angular Components and Their Files
Angular components can be categorized into different types based on their roles and responsibilities within the application.
Container Components
Container components are responsible for managing data and business logic. They often contain other components and provide data to them.
Example: Container Component
import { Component } from '@angular/core';
@Component({
selector: 'app-container',
templateUrl: './container.component.html',
styleUrls: ['./container.component.css']
})
export class ContainerComponent {
items = ['Item 1', 'Item 2', 'Item 3'];
}
Template (container.component.html
)
<div>
<ul>
<li *ngFor="let item of items">{{ item }}</li>
</ul>
</div>
Presentational Components
Presentational components focus on how things look. They receive data via inputs and emit events via outputs but contain little to no business logic.
Example: Presentational Component
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-presentational',
templateUrl: './presentational.component.html',
styleUrls: ['./presentational.component.css']
})
export class PresentationalComponent {
@Input() data: string;
}
Template (presentational.component.html
)
<div>
<p>{{ data }}</p>
</div>
Routing Components
Angular routing components control how various views are shown inside a single-page application and how navigation is handled. The capacity to create dynamic, interactive web apps that offer a flawless user experience is essential. The fundamentals of Angular routing, such as creating routes, identifying routing components, and controlling navigation between them, will be covered in this part.
Setting Up Angular Routing
To get started with Angular routing, you need to configure the router in your application. The router is responsible for interpreting URL paths and loading the corresponding components.
Step 1: Install Angular Router
If you haven’t already, ensure that Angular Router is installed. This is typically included with a new Angular project, but you can add it using:
ng add @angular/router
Step 2: Configure Routes in the App Module
Define your application’s routes in the app-routing.module.ts
file. Each route associates a path with a component.
app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
import { ContactComponent } from './contact/contact.component';
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'contact', component: ContactComponent },
{ path: '**', redirectTo: '', pathMatch: 'full' } // Redirect unknown routes to Home
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Step 3: Create the Routing Components
Next, generate the components that correspond to each route using the Angular CLI:
ng generate component home
ng generate component about
ng generate component contact
Adding Navigation Links
To enable navigation between these routes, you need to add links to your application template. Use the routerLink
directive to define the paths.
app.component.html
<nav>
<ul>
<li><a routerLink="">Home</a></li>
<li><a routerLink="about">About</a></li>
<li><a routerLink="contact">Contact</a></li>
</ul>
</nav>
<router-outlet></router-outlet>
Example: Routing Component
First, set up routing in your app-routing.module.ts
:
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { AboutComponent } from './about/about.component';
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
Home Component (home.component.ts
)
import { Component } from '@angular/core';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent { }
About Component (about.component.ts
)
import { Component } from '@angular/core';
@Component({
selector: 'app-about',
templateUrl: './about.component.html',
styleUrls: ['./about.component.css']
})
export class AboutComponent { }
Navigation Links (app.component.html
)
<nav>
<a routerLink="">Home</a>
<a routerLink="about">About</a>
</nav>
<router-outlet></router-outlet>
Interacting Between Components
Components often need to share data and communicate with each other. This can be achieved using various methods.
ViewChild and ContentChild
ViewChild
and ContentChild
allow one component to access the properties and methods of another component.
Example: Using ViewChild
import { Component, ViewChild, AfterViewInit } from '@angular/core';
import { ChildComponent } from './child/child.component';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css']
})
export class ParentComponent implements AfterViewInit {
@ViewChild(ChildComponent) child: ChildComponent;
ngAfterViewInit() {
console.log(this.child.childMessage);
this.child.childMessage = 'Updated by Parent Component!';
}
}
Service for Communication
Using a shared service is a common method for communication between components.
Step 1: Create the Service
ng generate
service data
Data Service (data.service.ts
)
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class DataService {
private messageSource = new BehaviorSubject<string>('Default Message');
currentMessage = this.messageSource.asObservable();
changeMessage(message: string) {
this.messageSource.next(message);
}
}
Step 2: Using the Service in Components
Parent Component (parent.component.ts
)
import { Component, OnInit } from '@angular/core';
import { DataService } from './data.service';
@Component({
selector: 'app-parent',
templateUrl: './parent.component.html',
styleUrls: ['./parent.component.css']
})
export class ParentComponent implements OnInit {
message: string;
constructor(private dataService: DataService) { }
ngOnInit() {
this.dataService.currentMessage.subscribe(message => this.message = message);
}
newMessage() {
this.dataService.changeMessage('Hello from Parent Component!');
}
}
Parent Template (parent.component.html
)
<div>
<p>Parent Message: {{ message }}</p>
<button (click)="newMessage()">New Message</button>
</div>
<app-child></app-child>
Child Component (child.component.ts
)
import { Component, OnInit } from '@angular/core';
import { DataService } from './data.service';
@Component({
selector: 'app-child',
templateUrl: './child.component.html',
styleUrls: ['./child.component.css']
})
export class ChildComponent implements OnInit {
message: string;
constructor(private dataService: DataService) { }
ngOnInit() {
this.dataService.currentMessage.subscribe(message => this.message = message);
}
}
Child Template (child.component.html
)
<div>
<p>Child Message: {{ message }}</p>
</div>
Conclusion
Angular Components serve as the cornerstone for constructing robust and sustainable applications. Understanding how to develop and utilize components, oversee their attributes, and facilitate communication between them empowers developers to harness the complete potential of Angular. Whether you’re handling straightforward UI elements or navigating intricate interactions, proficiency in Angular Components will substantially elevate your development prowess.