Table of Contents
- What Are Angular Components?
- Core Concepts of Angular Components
- Anatomy of an Angular Component
- Creating Your First Angular Component
- Component Interaction: Parent-Child Communication
- Component Lifecycle Hooks
- Component Styles and View Encapsulation
- Best Practices for Angular Components
- Conclusion
- References
1. What Are Angular Components?
In Angular, a component is a self-contained, reusable piece of code that controls a part of the UI (called a “view”). Think of components as Lego blocks: each block has a specific purpose (e.g., a button, a navigation bar, a user profile card) and can be combined with others to build a complete application.
Every Angular app has at least one component—the root component (typically AppComponent), which acts as the entry point for the application. All other components are nested within this root component or other child components, forming a hierarchical “component tree.”
2. Core Concepts of Angular Components
Before diving into implementation, let’s clarify the key ideas that define Angular components:
- Encapsulation: Components bundle logic, template (HTML), and styles (CSS) into a single unit, preventing style leakage and keeping code organized.
- Reusability: Components can be reused across the app (e.g., a
ButtonComponentorCardComponent). - Hierarchy: Components form a parent-child tree, where parents pass data to children, and children send events to parents.
- Lifecycle: Components go through a series of stages (creation, updates, destruction), with hooks to interact with these stages.
3. Anatomy of an Angular Component
An Angular component consists of three main parts:
- Component Class: Contains the logic (properties, methods) that controls the view.
- Template: The HTML that defines the component’s UI.
- Styles: CSS (or SCSS/Sass) that styles the component’s template.
These parts are glued together using the @Component decorator, which tells Angular that a class is a component and provides metadata about it.
3.1 The @Component Decorator
The @Component decorator is a function that takes a metadata object with properties like selector, templateUrl, and styleUrls. Here’s a breakdown of the most important metadata properties:
| Property | Purpose |
|---|---|
selector | A CSS-like selector that identifies the component in templates (e.g., <app-hello>). |
templateUrl | Path to an external HTML file for the template (e.g., ./hello.component.html). |
template | Inline HTML template (use instead of templateUrl for small templates). |
styleUrls | Array of paths to external style files (e.g., [./hello.component.css]). |
styles | Inline styles (use instead of styleUrls for small styles). |
encapsulation | Controls style encapsulation (default: ViewEncapsulation.Emulated). |
3.2 Example: Basic Component Structure
Let’s look at a simple HelloComponent to see how these parts come together:
// hello.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-hello', // Used in templates as <app-hello>
templateUrl: './hello.component.html', // External template
styleUrls: ['./hello.component.css'] // External styles
})
export class HelloComponent {
// Component logic (properties and methods)
userName: string = 'Angular Beginner';
greet(): string {
return `Hello, ${this.userName}!`;
}
}
<!-- hello.component.html (Template) -->
<h2>{{ greet() }}</h2>
<p>Welcome to Angular components!</p>
/* hello.component.css (Styles) */
h2 {
color: #2c3e50;
font-family: Arial, sans-serif;
}
p {
color: #7f8c8d;
}
4. Creating Your First Angular Component
The easiest way to create a component is using the Angular CLI (Command Line Interface). If you haven’t installed Angular CLI, run:
npm install -g @angular/cli
4.1 Step 1: Generate a Component with Angular CLI
Run this command in your Angular project to generate a component named user-profile:
ng generate component user-profile
# Shorthand: ng g c user-profile
The CLI creates four files in a src/app/user-profile folder:
user-profile.component.ts: The component class and@Componentdecorator.user-profile.component.html: The template.user-profile.component.css: The styles.user-profile.component.spec.ts: Test file (for unit tests).
4.2 Step 2: Explore the Generated Files
Let’s examine user-profile.component.ts:
import { Component } from '@angular/core';
@Component({
selector: 'app-user-profile',
templateUrl: './user-profile.component.html',
styleUrls: ['./user-profile.component.css']
})
export class UserProfileComponent {
// Add logic here (e.g., user data)
user = {
name: 'John Doe',
age: 30,
bio: 'Angular enthusiast and web developer.'
};
}
The template (user-profile.component.html) might look like this:
<div class="profile-card">
<h3>{{ user.name }}</h3>
<p>Age: {{ user.age }}</p>
<p>{{ user.bio }}</p>
</div>
4.3 Step 3: Use the Component in Another Template
To display UserProfileComponent, add its selector (<app-user-profile>) to a parent component’s template (e.g., app.component.html):
<!-- src/app/app.component.html -->
<h1>My App</h1>
<app-user-profile></app-user-profile> <!-- Renders the UserProfileComponent -->
Run ng serve to start the app, and you’ll see the user profile displayed!
5. Component Interaction: Parent-Child Communication
Components rarely exist in isolation. Most apps require parent components to share data with children, and children to send events back to parents.
5.1 Parent-to-Child: Pass Data with @Input()
Use the @Input() decorator to let a parent component pass data to a child.
Step 1: Define an @Input() property in the child component
// child.component.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
template: `<p>Parent message: {{ message }}</p>`
})
export class ChildComponent {
@Input() message!: string; // Data received from parent
}
Step 2: Pass data from the parent
In the parent’s template, bind to the child’s @Input() property:
<!-- parent.component.html -->
<app-child [message]="parentMessage"></app-child>
In the parent component class:
// parent.component.ts
export class ParentComponent {
parentMessage = 'Hello from Parent!'; // Data to send to child
}
5.2 Child-to-Parent: Emit Events with @Output()
Use @Output() with EventEmitter to let a child send data to its parent.
Step 1: Define an @Output() event in the child
// child.component.ts
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
template: `<button (click)="sendMessage()">Send to Parent</button>`
})
export class ChildComponent {
@Output() messageEvent = new EventEmitter<string>();
sendMessage() {
this.messageEvent.emit('Hello from Child!'); // Emit event with data
}
}
Step 2: Listen for the event in the parent
In the parent’s template, bind to the child’s @Output() event:
<!-- parent.component.html -->
<app-child (messageEvent)="receiveMessage($event)"></app-child>
<p>Child message: {{ childMessage }}</p>
In the parent class:
// parent.component.ts
export class ParentComponent {
childMessage!: string;
receiveMessage($event: string) {
this.childMessage = $event; // Data received from child
}
}
6. Component Lifecycle Hooks
Angular components go through a sequence of stages from creation to destruction. Lifecycle hooks are methods that let you run code at specific stages.
Here are the most commonly used hooks:
| Hook | Purpose |
|---|---|
ngOnInit() | Runs once after the component is initialized (use for fetching data). |
ngOnChanges() | Runs when input properties change (use to react to data updates). |
ngOnDestroy() | Runs before the component is destroyed (use for cleanup, e.g., unsubscribing). |
Example: Using ngOnInit() to Fetch Data
import { Component, OnInit } from '@angular/core';
import { UserService } from './user.service'; // Assume a service for data
@Component({ /* ... */ })
export class UserProfileComponent implements OnInit {
user: any;
constructor(private userService: UserService) {}
ngOnInit(): void {
// Fetch data when the component initializes
this.userService.getUser().subscribe(data => {
this.user = data;
});
}
}
7. Component Styles and View Encapsulation
By default, Angular encapsulates component styles, meaning styles defined in a component only apply to its template. This prevents conflicts with styles from other components.
7.1 View Encapsulation Modes
Angular offers three encapsulation modes (set via the encapsulation property in @Component):
ViewEncapsulation.Emulated(Default): Simulates shadow DOM by adding unique attributes to elements, scoping styles to the component.ViewEncapsulation.None: Disables encapsulation—styles become global.ViewEncapsulation.ShadowDom: Uses native shadow DOM for true encapsulation (browser support may vary).
Example: Disabling Encapsulation
@Component({
selector: 'app-global-styles',
template: `<p>Global style example</p>`,
styles: [`p { color: red; }`],
encapsulation: ViewEncapsulation.None // Styles apply globally
})
8. Best Practices for Angular Components
To write maintainable components, follow these guidelines:
- Single Responsibility: Each component should do one thing (e.g.,
UserProfileComponenthandles profile display, not data fetching). - Small Templates: Keep templates short. Split large templates into child components.
- Reuse Logic with Services: Move data-fetching or complex logic to services (e.g.,
UserService), not components. - Avoid Tight Coupling: Use
@Input()and@Output()instead of direct parent/child references. - Lazy Load Large Components: Use Angular’s lazy loading to load non-critical components only when needed.
9. Conclusion
Angular components are the backbone of any Angular application, enabling modular, reusable, and maintainable code. By mastering components—their anatomy, lifecycle, interaction, and best practices—you’ll be well on your way to building robust Angular apps.
Start small: create simple components, experiment with data binding, and gradually explore advanced topics like lifecycle hooks and encapsulation. The Angular ecosystem is vast, but components are your foundation.