Angular Components, Inputs and Outputs
🎧 Focus sounds
Soft beat sounds that many learners like while reading. Pick one, press Play, and keep studying.
Keep the volume low. These sounds are for comfort while studying, not a medical treatment. If you have epilepsy or are sensitive to pulsing sounds, use the background noise only.
In this lesson
Like React components, Angular components are reusable building blocks. A parent passes data in through inputs and listens to events coming out through outputs.
A component with inputs#
// src/app/course-card/course-card.component.ts
import { Component, computed, input, output } from '@angular/core';
export interface Course {
id: number;
title: string;
level: 'Beginner' | 'Intermediate' | 'Advanced';
price: number;
lessons: number;
}
@Component({
selector: 'app-course-card',
standalone: true,
template: `
<article class="card">
<h3>{{ course().title }} @if (isNew()) { <span class="badge">New</span> }</h3>
<p>{{ course().level }} · {{ course().lessons }} lessons</p>
<strong>{{ priceLabel() }}</strong>
<button (click)="enroll.emit(course())">Enroll</button>
</article>
`,
})
export class CourseCardComponent {
course = input.required<Course>(); // must be provided
isNew = input(false); // optional, default false
enroll = output<Course>(); // an event the parent can listen to
priceLabel = computed(() => (this.course().price === 0 ? 'Free' : `₹${this.course().price}`));
}
input.required<T>()andinput(default)create signal inputs: read them by calling them,course().output<T>()creates an event; call.emit(value)to send it.computed()derives a value that updates when its inputs change.
Older code uses decorators, which work the same way and you’ll see them everywhere:
@Input({ required: true }) course!: Course;
@Input() isNew = false;
@Output() enroll = new EventEmitter<Course>();
Using it from a parent#
// src/app/catalog/catalog.component.ts
import { Component, signal } from '@angular/core';
import { Course, CourseCardComponent } from '../course-card/course-card.component';
@Component({
selector: 'app-catalog',
standalone: true,
imports: [CourseCardComponent],
template: `
@for (c of courses; track c.id) {
<app-course-card [course]="c" [isNew]="c.id === 3" (enroll)="onEnroll($event)" />
}
@if (message()) {
<p role="status">{{ message() }}</p>
}
`,
})
export class CatalogComponent {
courses: Course[] = [
{ id: 1, title: 'Java Basics', level: 'Beginner', price: 499, lessons: 16 },
{ id: 2, title: 'HTML', level: 'Beginner', price: 0, lessons: 10 },
{ id: 3, title: 'Angular', level: 'Intermediate', price: 699, lessons: 12 },
];
message = signal('');
onEnroll(course: Course) {
this.message.set(`Enrolled in ${course.title}!`);
}
}
[course]="c"binds an input (square brackets: data into the child).(enroll)="onEnroll($event)"listens to an output (round brackets: events out of the child);$eventis the emitted value.
Content projection with ng-content#
Like React’s children, <ng-content> places whatever the parent puts between the tags:
// src/app/panel/panel.component.ts
import { Component, input } from '@angular/core';
@Component({
selector: 'app-panel',
standalone: true,
template: `
<section class="panel">
<header><h2>{{ title() }}</h2><ng-content select="[panel-actions]" /></header>
<div class="body"><ng-content /></div>
</section>
`,
})
export class PanelComponent {
title = input('');
}
<app-panel title="Your progress">
<button panel-actions>Reset</button> <!-- goes to the select="[panel-actions]" slot -->
<p>Java: 60% complete</p> <!-- goes to the default slot -->
</app-panel>
Lifecycle hooks#
| Hook | Runs |
|---|---|
constructor | when the class is created (inject dependencies here; inputs aren’t set yet) |
ngOnInit | once, after the first inputs are set: load data here |
ngOnChanges(changes) | when decorator @Inputs change |
ngAfterViewInit | after the component’s view (and children) is rendered: access DOM via viewChild |
ngOnDestroy | before the component is removed: clean up timers and subscriptions |
export class ClockComponent implements OnInit, OnDestroy {
now = signal(new Date());
private timer?: ReturnType<typeof setInterval>;
ngOnInit() { this.timer = setInterval(() => this.now.set(new Date()), 1000); }
ngOnDestroy() { clearInterval(this.timer); }
}
With signal inputs, most “react to input changes” logic becomes computed() or effect() instead of ngOnChanges.
Component styles are scoped#
Styles in a component’s styles/styleUrl apply only to that component’s template (Angular adds unique attributes behind the scenes). .card in CourseCardComponent won’t leak into other components. Global styles go in src/styles.css.
Split components into presentational (“dumb”) components that only use inputs/outputs (like CourseCard) and container (“smart”) components that talk to services (like Catalog). Presentational components are easy to reuse and test.
Exercise#
- Create a
UserBadgeComponentwithname(required) androle(default “Student”) inputs. - Add a
removeoutput toCourseCardComponentand remove the course from the parent’s list when it fires. - Build a
ModalComponentwith a title input, projected content and aclosedoutput. - Add a
ClockComponentand check (withconsole.log) thatngOnDestroyruns when it’s hidden with@if.
Hint for 2
Make courses a signal in the parent: courses = signal<Course[]>([...]) and onRemove(c: Course) { this.courses.update(list => list.filter(x => x.id !== c.id)); }.
Interview corner#
- @Input vs @Output? Inputs pass data from parent to child; outputs emit events from child to parent.
- What is content projection? Inserting parent-provided content into a child’s template with
<ng-content>. - constructor vs ngOnInit? Constructor for DI and simple setup; ngOnInit after inputs are initialised, for data loading.
- What are signal inputs?
input()/input.required()that expose inputs as read-only signals.
Summary#
- Inputs (
input(),@Input) bring data in; outputs (output(),@Output) send events out. <ng-content>projects parent content; component styles are scoped.- Lifecycle hooks: init in
ngOnInit, clean up inngOnDestroy.
Next: the four kinds of data binding, animated.
Quick quiz
3 questions. Check what stuck and earn 2 XP for each right answer.
Progress is saved in this browser. Create a free account to keep it on every device.
Get new lessons in your inbox
One email when we publish a new tutorial or guide. No spam, unsubscribe in one click.