Angular components are the fundamental building blocks of Angular applications. Each component controls a part of the user interface (UI) and is responsible for displaying data, handling user interaction, and providing functionality.
Understanding Angular components is crucial for any Angular developer, from beginners to advanced. Let’s break down Angular components from the fundamentals to more advanced concepts, with simple examples for each.
What is an Angular Component?
An Angular component is a class that defines a view, and its associated logic, and controls how a section of the UI behaves. Each component in Angular has:
A Template (HTML view) that defines the structure of the UI.
A Class (TypeScript code) that defines the logic and behavior of the view.
Styles (CSS or SCSS) to define the appearance of the component.
1. Component Structure
At the core, a component consists of:
Component Class (written in TypeScript)
Template (HTML)
Styles (CSS/SCSS)
Metadata (decorated with
@Component
decorator)
Example of a Basic Angular Component
Let’s go step-by-step to create a simple Angular component:
Step 1: Create a Component
You can generate a component using Angular CLI:
bashCopy codeng generate component user
This generates:
user.component.ts (component class)
user.component.html (template)
user.component.css (styles)
user.component.spec.ts (for testing)
Step 2: Basic Component Class (user.component.ts
)
typescriptCopy codeimport { Component } from '@angular/core';
@Component({
selector: 'app-user', // The tag to represent the component in HTML
templateUrl: './user.component.html', // The HTML template for the component
styleUrls: ['./user.component.css'] // The styles for the component
})
export class UserComponent {
username = 'John Doe'; // Property to bind to template
constructor() { }
changeUsername(newName: string) {
this.username = newName; // Method to update the username
}
}
Step 3: Component Template (user.component.html
)
htmlCopy code<div class="user-container">
<h2>Welcome, {{ username }}!</h2> <!-- Interpolation binding -->
<button (click)="changeUsername('Jane Smith')">Change Username</button> <!-- Event binding -->
</div>
Step 4: Component Styles (user.component.css
)
cssCopy code.user-container {
background-color: #f0f0f0;
padding: 20px;
border-radius: 5px;
text-align: center;
}
button {
padding: 10px 20px;
font-size: 16px;
}
Key Concepts in Angular Components
Component Decorator (@Component)
The
@Component
decorator tells Angular that the class is a component and provides metadata for Angular to understand how it should be processed.The metadata includes:
selector: The custom HTML tag used to represent the component.
templateUrl: The path to the component’s HTML template.
styleUrls: The path to the component’s styles.
Component Class
- The class defines properties (data) and methods (logic) to manage the view. It can also interact with services, handle user input, and perform other tasks.
Template
- The template defines the structure of the UI and how it connects to the component class. It uses Angular directives like
*ngIf
,*ngFor
, etc., and Angular binding techniques like interpolation, property binding, event binding, and two-way binding.
- The template defines the structure of the UI and how it connects to the component class. It uses Angular directives like
Styles
- Styles control the look and feel of the component. You can use global styles or component-specific styles, which are scoped to that component.
Advanced Concepts in Angular Components
After understanding the basics of components, let’s dive into more advanced topics.
1. Lifecycle Hooks
Angular components have lifecycle hooks that allow you to tap into different stages of the component’s lifecycle.
Some of the most commonly used lifecycle hooks:
ngOnInit(): Called once after the component is initialized (good for data fetching or setup).
ngOnChanges(): Called whenever an input property of the component changes.
ngOnDestroy(): Called just before the component is destroyed (good for cleanup tasks).
ngAfterViewInit(): Called after the component’s view has been fully initialized.
Example: Using ngOnInit()
:
typescriptCopy codeimport { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {
username: string;
ngOnInit() {
this.username = 'Initializing...';
setTimeout(() => {
this.username = 'John Doe'; // Simulate a data fetch
}, 2000);
}
}
2. Input and Output Properties (Data Binding between Components)
In Angular, components can communicate with each other using @Input and @Output.
@Input(): Allows a parent component to pass data to a child component.
@Output(): Allows a child component to emit an event that the parent component can listen to.
Example: Parent-Child Communication:
Parent Component (AppComponent) (app.component.ts
)
typescriptCopy codeimport { Component } from '@angular/core';
@Component({
selector: 'app-root',
template: `<app-user [username]="parentUsername" (usernameChanged)="updateUsername($event)"></app-user>`,
styleUrls: ['./app.component.css']
})
export class AppComponent {
parentUsername = 'Parent User';
updateUsername(newName: string) {
this.parentUsername = newName;
}
}
Child Component (UserComponent) (user.component.ts
)
typescriptCopy codeimport { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-user',
templateUrl: './user.component.html',
styleUrls: ['./user.component.css']
})
export class UserComponent {
@Input() username: string; // Input property
@Output() usernameChanged = new EventEmitter<string>(); // Output property
changeUsername() {
this.usernameChanged.emit('New Username');
}
}
Child Template (user.component.html
)
htmlCopy code<div>
<h2>{{ username }}</h2>
<button (click)="changeUsername()">Change Username</button>
</div>
3. Dynamic Components
Sometimes, you may need to load components dynamically. This can be achieved using ComponentFactoryResolver
and ViewContainerRef
.
Example of Dynamic Component Loading:
typescriptCopy codeimport { Component, ComponentFactoryResolver, ViewChild, ViewContainerRef } from '@angular/core';
import { DynamicComponent } from './dynamic.component';
@Component({
selector: 'app-root',
template: `<button (click)="loadComponent()">Load Dynamic Component</button>
<ng-container #dynamicComponentContainer></ng-container>`,
styleUrls: ['./app.component.css']
})
export class AppComponent {
@ViewChild('dynamicComponentContainer', { read: ViewContainerRef }) container: ViewContainerRef;
constructor(private componentFactoryResolver: ComponentFactoryResolver) {}
loadComponent() {
const componentFactory = this.componentFactoryResolver.resolveComponentFactory(DynamicComponent);
this.container.clear(); // Clear previous components
this.container.createComponent(componentFactory);
}
}
4. Component Inheritance
You can extend a component class to reuse functionality across multiple components.
Example of Component Inheritance:
typescriptCopy codeimport { Component } from '@angular/core';
class BaseComponent {
title = 'Base Component';
}
@Component({
selector: 'app-child',
template: `<h1>{{ title }}</h1>`
})
export class ChildComponent extends BaseComponent {
constructor() {
super();
this.title = 'Child Component'; // Overridden title
}
}
Conclusion
Components are the heart of Angular applications, representing both the UI and the logic.
They consist of HTML templates, TypeScript logic, and CSS styles.
You can use lifecycle hooks to tap into the component's lifecycle and @Input and @Output to communicate between parent and child components.
More advanced topics include dynamic components and component inheritance.