This pattern helps separate how data is handled from how it looks. It makes your app easier to understand and change.
Smart and dumb component pattern in Angular
Start learning this pattern below
Jump into concepts and practice - no test required
/* Smart component (container) */ @Component({ selector: 'app-smart', standalone: true, imports: [DumbComponent], template: `<app-dumb [items]="items" (select)="onSelect($event)"></app-dumb>` }) export class SmartComponent { items = ['Apple', 'Banana', 'Cherry']; onSelect(item: string) { console.log('Selected:', item); } } /* Dumb component (presentational) */ @Component({ selector: 'app-dumb', standalone: true, imports: [CommonModule], template: ` <ul> <li *ngFor="let item of items" (click)="select.emit(item)" tabindex="0" role="button" aria-label="Select {{item}}"> {{item}} </li> </ul> ` }) export class DumbComponent { @Input() items: string[] = []; @Output() select = new EventEmitter<string>(); }
The smart component holds data and logic.
The dumb component only shows data and sends user actions back.
/* Dumb component only shows data */ @Component({ selector: 'app-dumb', standalone: true, template: `<p>{{message}}</p>`, inputs: ['message'] }) export class DumbComponent { @Input() message = ''; }
/* Smart component passes data and handles events */ @Component({ selector: 'app-smart', standalone: true, imports: [DumbComponent], template: `<app-dumb [message]="greeting"></app-dumb>` }) export class SmartComponent { greeting = 'Hello from smart component!'; }
The smart component holds a list of fruits and passes it to the dumb component. The dumb component shows the list and lets the user click an item. When clicked, the dumb component tells the smart component which item was selected. The smart component then logs the selection.
import { Component, EventEmitter, Input, Output } from '@angular/core'; import { CommonModule } from '@angular/common'; @Component({ selector: 'app-dumb', standalone: true, imports: [CommonModule], template: ` <ul> <li *ngFor="let item of items" (click)="select.emit(item)" tabindex="0" role="button" aria-label="Select {{item}}"> {{item}} </li> </ul> ` }) export class DumbComponent { @Input() items: string[] = []; @Output() select = new EventEmitter<string>(); } @Component({ selector: 'app-smart', standalone: true, imports: [DumbComponent], template: `<app-dumb [items]="items" (select)="onSelect($event)"></app-dumb>` }) export class SmartComponent { items = ['Apple', 'Banana', 'Cherry']; onSelect(item: string) { console.log('Selected:', item); } }
Use @Input() to send data to dumb components.
Use @Output() with EventEmitter to send events back to smart components.
Keep dumb components free of data fetching or complex logic.
Smart components manage data and logic.
Dumb components focus on displaying data and user interaction.
This pattern makes your app easier to maintain and test.
Practice
smart component in Angular's smart and dumb component pattern?Solution
Step 1: Understand smart component responsibilities
Smart components are designed to handle data fetching, state management, and business logic.Step 2: Differentiate from dumb components
Dumb components focus on displaying data and emitting events, not managing data or logic.Final Answer:
To manage data and business logic -> Option CQuick Check:
Smart component = data and logic [OK]
- Confusing dumb components as managing data
- Thinking smart components only display UI
- Assuming smart components handle styling only
Solution
Step 1: Identify data flow direction
Data flows from smart to dumb components via inputs.Step 2: Use Angular syntax for input binding
Dumb components declare@Input()properties to receive data from parents.Final Answer:
@Input() data: any; -> Option DQuick Check:
Data to dumb = @Input() [OK]
- Using @Output() to pass data down instead of events up
- Trying to access dumb component data directly via ViewChild
- Modifying dumb component state via services without inputs
/* Smart component template */
<app-dumb [title]="pageTitle" (clicked)="onClicked()"></app-dumb>
/* Smart component class */
pageTitle = 'Hello World';
onClicked() { console.log('Clicked!'); }
/* Dumb component template */
<h1>{{ title }}</h1>
<button (click)="clicked.emit()">Click Me</button>
/* Dumb component class */
@Input() title: string;
@Output() clicked = new EventEmitter<void>();Solution
Step 1: Analyze data binding from smart to dumb
The smart component passes 'Hello World' via[title]input, so dumb displays it.Step 2: Analyze event emission and handling
The dumb component emitsclickedevent on button click, smart component listens and logs 'Clicked!'.Final Answer:
Displays 'Hello World' and logs 'Clicked!' on button click -> Option AQuick Check:
Input shows title, output triggers log [OK]
- Thinking dumb component logs directly
- Assuming missing decorators cause runtime error here
- Ignoring event binding from dumb to smart
@Component({
selector: 'app-dumb',
template: `<button (click)="clicked.emit()">Click</button>`
})
export class DumbComponent {
clicked = new EventEmitter<void>();
}Solution
Step 1: Check event emitter declaration
Theclickedproperty must have@Output()decorator to emit events to parent.Step 2: Verify imports and syntax
EventEmitter is correctly imported from '@angular/core', template syntax is correct.Final Answer:
Missing @Output() decorator on the clicked property -> Option BQuick Check:
@Output() missing = no event emission [OK]
- Forgetting @Output() decorator
- Importing EventEmitter from wrong package
- Miswriting template event binding syntax
Solution
Step 1: Separate concerns by responsibility
Smart components should handle data fetching and logic, dumb components focus on UI and user interaction.Step 2: Use Angular bindings correctly
Pass data from smart to dumb via@Input()and receive events via@Output().Final Answer:
Create a smart component to fetch data and handle logic, pass data via @Input() to dumb components that only display UI and emit events -> Option AQuick Check:
Smart = logic/data, Dumb = UI only [OK]
- Putting logic in dumb components
- Merging smart and dumb components unnecessarily
- Reversing data flow direction
