RxJS distinctUntilChanged
distinctUntilChanged is used to prevent emitting duplicate consecutive values in a stream.
✅ Example Use Case
Let’s assume you have an input box and want to perform a search only when the input value changes (distinct), and not on every key stroke with the same value.
💡 Step-by-Step Implementation
- Angular Component HTML
<input type="text" [formControl]="searchControl" placeholder="Search here..." />2. Angular Component TypeScript
import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
@Component({
selector: 'app-search',
templateUrl: './search.component.html'
})
export class SearchComponent implements OnInit {
searchControl = new FormControl('');
ngOnInit(): void {
this.searchControl.valueChanges
.pipe(
debounceTime(300), // wait for 300ms pause in events
distinctUntilChanged() // only emit when value is different from previous
)
.subscribe(value => {
console.log('Search term:', value);
// You can call a search API here
});
}
}🧠 What’s Happening Here?
✅ valueChanges: Emits every time the input value changes.
✅ debounceTime(300): Waits for 300ms after the user stops typing.
✅ distinctUntilChanged(): Prevents emitting the same value consecutively.
🍔 Analogy: Fast-Food Order Display
Imagine a screen in a fast-food kitchen that shows the latest order to the chefs.
Without distinctUntilChanged
Every time a customer sends any order — even if it’s the same as the previous one, it shows up on the screen
Order: Burger 🍔 → Displayed
Order: Burger 🍔 (again) → Displayed again (unnecessarily)With distinctUntilChanged
Get The Frontend Fuel’s stories in your inbox
Join Medium for free to get updates from this writer.
The system checks: “Is this order the same as the last one?” If yes, skip it!
Order: Burger 🍔 → Displayed
Order: Burger 🍔 → Ignored (already cooking it!)
Order: Fries 🍟 → Displayed
Order: Fries 🍟 → IgnoredThis way, only new or changed inputs trigger actions — saving effort, time, and processing.
Let’s build a complete example using
⚙️ FormControl for capturing user input
⚙️ debounceTime to wait for user to stop typing
⚙️ distinctUntilChanged to ignore duplicate searches
⚙️ filter to ignore short/empty values
⚙️ switchMap to cancel previous requests and call an API only for the latest input
✅ Scenario: Real-Time Search (e.g., search users by name)
<input type="text" [formControl]="searchControl" placeholder="Search user..." />
<ul>
<li *ngFor="let user of users">{{ user.name }}</li>
</ul>⚙️ 2. Component TS
import { Component, OnInit } from '@angular/core';
import { FormControl } from '@angular/forms';
import { debounceTime, distinctUntilChanged, filter, switchMap } from 'rxjs/operators';
import { of } from 'rxjs';
import { UserService } from './user.service';
@Component({
selector: 'app-user-search',
templateUrl: './user-search.component.html'
})
export class UserSearchComponent implements OnInit {
searchControl = new FormControl('');
users: any[] = [];
constructor(private userService: UserService) {}
ngOnInit(): void {
this.searchControl.valueChanges.pipe(
debounceTime(300),
filter(value => value && value.length > 2), // only if 3+ characters
distinctUntilChanged(),
switchMap(query => this.userService.searchUsers(query)) // cancels old request
).subscribe(result => {
this.users = result;
});
}
}🔌 3. User Service (Simulated API Call)
import { Injectable } from '@angular/core';
import { of } from 'rxjs';
import { delay } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class UserService {
private dummyUsers = [
{ name: 'Alice' },
{ name: 'Bob' },
{ name: 'Charlie' },
{ name: 'David' }
];
searchUsers(query: string) {
const filtered = this.dummyUsers.filter(user =>
user.name.toLowerCase().includes(query.toLowerCase())
);
return of(filtered).pipe(delay(500)); // simulate network delay
}
}🚀 Flow Summary:
⚙️ User types → waits 300ms
⚙️ If input is 3+ characters and has changed → API call is made
⚙️ If the user types again quickly → previous request is canceled (thanks to switchMap)








