Angular Components¶
🎯 Hands-On Module: This is where Angular development gets practical! You'll create your first component and learn how components work by building real examples. Follow along with the exercises and experiment with the code.
What are Components?¶
Components are the fundamental building blocks of Angular applications. Think of them as custom HTML elements that you create to build your user interface. A component controls a portion of the screen through its template and manages the data and behavior for that view.
In simple terms: A component is like a reusable piece of UI that combines:
- Logic (what it does)
- Template (how it looks)
- Styles (how it's styled)
Component Anatomy¶
Every Angular component consists of:
- TypeScript Class - Contains the component logic (properties, methods)
- HTML Template - Defines the view structure (what you see)
- CSS Styles - Defines the appearance (colors, fonts, layout)
- Metadata - Tells Angular how to process the component (@Component decorator)
🛠️ Step 0: Setting Up Our Demo Project¶
Before we start creating components, let's set up a clean demo project to work with.
Create the Demo Project¶
cd /path/to/your/workspace
ng new angular-module4-demo --routing --style=css --skip-git
cd angular-module4-demo
Clean Up the Default Template¶
The default Angular template has a lot of content. Let's replace it with a minimal setup:
- Open
src/app/app.htmland replace ALL content with within the placeholder with the following:
Your file should now look like this:
<main class="main">
<div class="content">
<h1>Angular Module 4 Demo</h1>
</div>
</main>
<router-outlet />
- Open
src/app/app.cssand add minimal styling:
.main {
margin: auto 0;
}
.content {
padding: 20px;
font-family: Arial, sans-serif;
}
h1 {
color: #2c3e50;
text-align: center;
}
- Test your setup:
Visit http://localhost:4200 - you should see a clean page with "Angular Module 4 Demo" as the title.
You should see something like this:

🛠️ Hands-On: Creating Your First Component¶
Let's create a practical component step by step! We'll build a greeting component that displays a personalized message.
Step 1: Generate the Component¶
Now let's create our first custom component! A greeting component that displays a simple message.
Open your terminal in the demo project and run:
cd angular-module4-demo # if not already in the project directory
ng generate component greeting
# or shorthand:
ng g c greeting
What this creates in Angular 20:
src/app/greeting/greeting.ts- Component classsrc/app/greeting/greeting.html- Templatesrc/app/greeting/greeting.css- Stylessrc/app/greeting/greeting.spec.ts- Unit tests
Note: Angular 20 uses simplified file naming (no
.componentin filenames) and standalone components by default.
Step 2: Create a Simple Greeting Component¶
Let's keep it minimal! Add the message property to the component class to display it in the template.
src/app/greeting/greeting.ts¶
import { Component } from '@angular/core';
@Component({
selector: 'app-greeting',
imports: [],
templateUrl: './greeting.html',
styleUrl: './greeting.css'
})
export class Greeting {
message = 'Hello from the Greeting Component!';
}
src/app/greeting/greeting.html¶
Now open src/app/greeting/greeting.html and replace the existing content with:
The {{ message }} syntax is called interpolation and it allows us to display the value of the message property in the template.
src/app/greeting/greeting.css¶
To make the component look nice, let's add some styles. Open src/app/greeting/greeting.css and add the following:
.greeting {
padding: 20px;
border: 2px solid #3498db;
border-radius: 8px;
margin: 20px 0;
background-color: #f8f9fa;
text-align: center;
}
h2 {
color: #2c3e50;
margin: 0;
}
Step 3: Use the Component in Our App¶
Now let's add our greeting component to the main app. There are some steps needed.
First we need to make the app aware of our new component.
To do this we need to add the import to the app.ts file, include it in the root component, and include it in the template.
- Import the component in
src/app/app.ts:
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { Greeting } from './greeting/greeting'; // import the Greeting component
@Component({
selector: 'app-root',
imports: [RouterOutlet, Greeting], // add Greeting to imports
templateUrl: './app.html',
styleUrl: './app.css'
})
export class App {
protected title = 'angular-module4-demo';
}
- Add the component to
src/app/app.html:
<main class="main">
<div class="content">
<h1>Angular Module 4 Demo</h1>
<app-greeting></app-greeting>
</div>
</main>
<router-outlet />
Step 4: Test Your First Component¶
Your development server should automatically reload. Visit http://localhost:4200 and you should see:
- The main title "Angular Module 4 Demo"
- Below it, a blue-bordered box with "Hello from the Greeting Component!"
Your page should look something like this:

🎉 Congratulations! You've just created and used your first Angular component!
Step 5: Adding a Simple Counter Component¶
Now let's create a second component that demonstrates dynamic data and event handling. We'll build a simple counter that you can increment and reset.
Generate the Counter Component¶
Create the Counter Component¶
Keep it minimal! Replace the generated counter component with:
src/app/counter/counter.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-counter',
imports: [],
templateUrl: './counter.html',
styleUrl: './counter.css'
})
export class Counter {
count = 0;
increment() {
this.count++;
}
reset() {
this.count = 0;
}
}
src/app/counter/counter.html
<div class="counter">
<h3>Counter: {{ count }}</h3>
<button (click)="increment()">+1</button>
<button (click)="reset()">Reset</button>
</div>
src/app/counter/counter.css
.counter {
padding: 20px;
border: 2px solid #e74c3c;
border-radius: 8px;
margin: 20px 0;
background-color: #fdf2f2;
text-align: center;
}
button {
margin: 0 5px;
padding: 8px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-weight: bold;
}
button:first-of-type {
background-color: #27ae60;
color: white;
}
button:last-of-type {
background-color: #e74c3c;
color: white;
}
Add Counter to Main App¶
- Import the counter in
src/app/app.ts:
import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { Greeting } from './greeting/greeting';
import { Counter } from './counter/counter'; // import Counter
@Component({
selector: 'app-root',
imports: [RouterOutlet, Greeting, Counter], // add Counter to imports
templateUrl: './app.html',
styleUrl: './app.css'
})
export class App {
protected title = 'angular-module4-demo';
}
- Add counter to template in
src/app/app.html:
<main class="main">
<div class="content">
<h1>Angular Module 4 Demo</h1>
<app-greeting></app-greeting>
<app-counter></app-counter>
</div>
</main>
<router-outlet />
Test Your Counter¶
Visit http://localhost:4200 and you should now see:
- Your greeting component (blue border)
- Below it, a counter component (red border) with buttons that work!
Try clicking the "+1" and "Reset" buttons to see the dynamic behavior!
Your browser should look like this:

🎯 What You've Learned:
- Data binding with
{{ count }} - Event handling with
(click)="method()" - Component methods that modify data
- Multiple components in one app
Step 5: Adding a Dynamic Message¶
Understanding Component Decorator¶
The @Component decorator is what makes a TypeScript class into an Angular component. Let's understand its key properties:
@Component({
selector: 'app-greeting', // HTML tag name: <app-greeting></app-greeting>
imports: [], // Other components/directives this component uses
templateUrl: './greeting.html', // External template file
styleUrl: './greeting.css' // External style file (Angular 20 uses styleUrl, not styleUrls)
// Alternative inline options (for small components):
// template: '<h1>Inline Template</h1>',
// styles: ['h1 { color: blue; }']
})
Key Decorator Properties Explained¶
- selector: The custom HTML tag name for your component
- Convention:
app-prefix followed by component name -
Used like:
<app-greeting></app-greeting> -
imports: Dependencies your component needs
- Other components, directives, pipes
-
Angular 20 standalone components manage their own dependencies
-
templateUrl / template: Where to find the HTML template
templateUrl: External file (recommended for complex templates)-
template: Inline HTML (good for simple components) -
styleUrl / styles: Component-specific CSS
styleUrl: External CSS file (Angular 20 syntax)styles: Inline CSS array
🔍 Angular 20 Changes:
styleUrlinstead ofstyleUrls(simplified)importsinstead of module declarations- Standalone components by default (no NgModules required)
Understanding Data Binding¶
Now that we've created our basic components, let's understand how data binding works with real examples from our demo project.
1. Interpolation - Displaying Data¶
How it works: Display component properties in the template using {{ }}.
Our greeting component already demonstrates this perfectly:
// In greeting.ts (what we already created)
export class Greeting {
message = 'Hello from Angular 20!';
}
<!-- In greeting.html (what we already created) -->
<div class="greeting">
<h2>{{ message }}</h2>
</div>
Key Point: The {{ message }} displays the value of the message property. When the property changes, the display updates automatically.
2. Event Binding - Handling User Actions¶
How it works: Listen to user events using (event)="method()".
Our counter component demonstrates this with its buttons:
// In counter.ts (what we already created)
export class Counter {
count = 0;
increment() {
this.count++;
}
reset() {
this.count = 0;
}
}
<!-- In counter.html (what we already created) -->
<div class="counter">
<h3>Count: {{ count }}</h3>
<button (click)="increment()">+1</button>
<button (click)="reset()">Reset</button>
</div>
Key Points:
(click)="increment()"listens for click events- When clicked, it calls the
increment()method - The method updates the
countproperty - Angular automatically updates the display
3. Property Binding - Setting Element Properties¶
Now that we have a basic understanding of data binding through our examples, let's explore property binding.
How it works: Set element properties and attributes using [property]="value".
Let's enhance our counter component to demonstrate property binding by making it more dynamic:
// Enhanced counter.ts
export class Counter {
count = 0;
maxCount = 10;
step = 1;
increment() {
if (this.count < this.maxCount) {
this.count += this.step;
}
}
reset() {
this.count = 0;
}
get isAtMax() {
return this.count >= this.maxCount;
}
get isHighCount() {
return this.count >= 7;
}
}
<!-- Enhanced counter.html with property binding -->
<div class="counter" [class.high-count]="isHighCount">
<h3>Count: {{ count }}</h3>
<button
(click)="increment()"
[disabled]="isAtMax"
[title]="isAtMax ? 'Maximum reached!' : 'Increment by ' + step">
+{{ step }}
</button>
<button
(click)="reset()"
[title]="'Reset count to 0'">
Reset
</button>
<p [style.color]="isHighCount ? 'orange' : 'green'">
{{ isAtMax ? 'Maximum reached!' : count + ' of ' + maxCount }}
</p>
</div>
/* Enhanced counter.css - add this to your existing styles */
.counter.high-count {
border-color: #f39c12;
background-color: #fef9e7;
}
.counter button[disabled] {
background-color: #95a5a6;
cursor: not-allowed;
opacity: 0.6;
}
.counter button[title]:hover::after {
content: attr(title);
position: absolute;
background: #333;
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 12px;
white-space: nowrap;
z-index: 1000;
}
Key Points:
[disabled]="isAtMax"- Disables button when condition is true[class.high-count]="isHighCount"- Adds CSS class conditionally[title]="..."- Sets tooltip text dynamically[style.color]="..."- Sets inline styles based on conditions- Square brackets
[]indicate property binding
What this demonstrates:
- Conditional styling - Border and background change when count is high
- Dynamic attributes - Button tooltip changes based on state
- Disabled state - Button becomes unclickable at maximum
- Conditional classes - CSS class applied when count >= 7
Your app should now look like this:

🎯 Exercise: Enhance Your Components¶
Now that you understand the basics, try enhancing the components we created:
For the Greeting Component:
- Add a
nameproperty and display "Hello, [name]!" - Add a method to change the greeting message
- Add a button that calls the method
For the Counter Component:
- Add a decrement button (
-1) - Add a step size (increment/decrement by 2, 5, etc.)
- Add a maximum limit (can't go above 10)
- Change the border color when count is high
Challenge: Create a new component that combines both greeting and counting!
Advanced Topics (Optional)¶
The sections below cover more advanced component concepts. These are important for larger applications but not essential for getting started. Feel free to explore them when you're comfortable with the basics.
Lifecycle Hooks Interface¶
import { Component, OnInit, OnDestroy, OnChanges, SimpleChanges } from '@angular/core';
@Component({
selector: 'app-lifecycle-demo',
standalone: true,
template: `
<h3>Lifecycle Demo</h3>
<p>Check the console for lifecycle events</p>
`
})
export class LifecycleDemoComponent implements OnInit, OnChanges, OnDestroy {
constructor() {
console.log('Constructor called');
}
ngOnChanges(changes: SimpleChanges) {
console.log('OnChanges called', changes);
}
ngOnInit() {
console.log('OnInit called');
// Component initialization logic here
}
ngDoCheck() {
console.log('DoCheck called');
}
ngAfterContentInit() {
console.log('AfterContentInit called');
}
ngAfterContentChecked() {
console.log('AfterContentChecked called');
}
ngAfterViewInit() {
console.log('AfterViewInit called');
}
ngAfterViewChecked() {
console.log('AfterViewChecked called');
}
ngOnDestroy() {
console.log('OnDestroy called');
// Cleanup logic here
}
}
Lifecycle Hook Order¶
- Constructor - TypeScript class constructor
- OnChanges - When input properties change
- OnInit - After first OnChanges
- DoCheck - Custom change detection
- AfterContentInit - After content projection
- AfterContentChecked - After every content check
- AfterViewInit - After component view initialization
- AfterViewChecked - After every view check
- OnDestroy - Just before Angular destroys the component
Component Communication¶
In our demo app, we have multiple components working together. Let's understand how components can communicate.
Simple Component Communication Example¶
Right now our app.ts file imports and uses both components:
// In app.ts
import { Component } from '@angular/core';
import { Greeting } from './greeting/greeting';
import { Counter } from './counter/counter';
@Component({
selector: 'app-root',
imports: [Greeting, Counter],
templateUrl: './app.html',
styleUrl: './app.css'
})
export class App {
title = 'angular-module4-demo';
}
Parent to Child - Input Properties¶
Let's enhance our demo to show data passing. We could modify our greeting component to accept a name:
// Enhanced greeting.ts
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-greeting',
imports: [],
templateUrl: './greeting.html',
styleUrl: './greeting.css'
})
export class Greeting {
@Input() name = 'World'; // Can receive name from parent
get message() {
return `Hello, ${this.name}!`;
}
}
Then the parent can pass data:
Child to Parent - Output Properties¶
We could enhance our counter to notify the parent when the count changes:
// Enhanced counter.ts
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-counter',
imports: [],
templateUrl: './counter.html',
styleUrl: './counter.css'
})
export class Counter {
count = 0;
@Output() countChange = new EventEmitter<number>();
increment() {
this.count++;
this.countChange.emit(this.count); // Notify parent
}
reset() {
this.count = 0;
this.countChange.emit(this.count); // Notify parent
}
}
And the parent can listen:
<!-- In app.html -->
<app-counter (countChange)="onCountChange($event)"></app-counter>
<p>Counter changed to: {{ currentCount }}</p>
// In app.ts
export class App {
currentCount = 0;
onCountChange(newCount: number) {
this.currentCount = newCount;
console.log('Count changed to:', newCount);
}
}
Key Points:
@Input()brings data INTO a component from its parent@Output()sends events OUT of a component to its parent- This creates a clear data flow: down through inputs, up through outputs
💡 Note: For more advanced component communication patterns like services, observables, and complex parent-child relationships, see Module 9: Component Communication.
Summary¶
Congratulations! You've learned the fundamentals of Angular components by building real examples:
What We Built:
- ✅ Demo Project: Clean Angular 20 setup
- ✅ Greeting Component: Simple interpolation example
- ✅ Counter Component: Event handling and state management
- ✅ Working App: Multiple components working together
Key Concepts Covered:
- Component Structure: TypeScript class + HTML template + CSS styles
- Data Binding: Interpolation (
{{}}) and event binding ((click)) - Component Communication: Input/Output patterns for data flow
- Angular 20 Features: Standalone components,
styleUrl, simplified imports
Practice Suggestions:
Keep experimenting with the demo project:
- Add more properties to the greeting component
- Create a new component that combines greeting and counting
- Try passing data between the components
- Style the components differently
The best way to learn Angular is by building things - you're off to a great start!
Next Steps¶
Now that you understand the fundamentals of Angular components, you're ready to dive deeper:
- Module 5: Angular Modules and Module System - Learn how to organize your application into feature modules
- Module 7: Introduction to Angular Templates - Master template syntax and make your components more dynamic
- Module 8: Data Binding - Master all types of data binding in detail
- Module 9: Component Communication - Learn advanced patterns for component interaction
- Module 17: Advanced Components - Explore advanced component features like content projection, lifecycle hooks, and architectural patterns
Quick Reference¶
Component Anatomy (What You Built)¶
@Component({
selector: 'app-greeting', // Custom HTML tag
imports: [], // Dependencies
templateUrl: './greeting.html', // Template file
styleUrl: './greeting.css' // Styles file
})
export class Greeting {
message = 'Hello from Angular!'; // Component property
// Component methods go here
}
What You've Learned¶
- Interpolation:
{{ message }}- Display component data - Event Binding:
(click)="increment()"- Handle user interactions - Property Binding:
[disabled]="isAtMax"- Set element properties dynamically - Component Methods: Functions that respond to events and update data
- Component Properties: Data that gets displayed in the template
Keep practicing with the demo project and experiment with these concepts!