Angular + RxJS : count
February 07, 2024
On this page we will learn to use RxJS count
operator in our Angular application. RxJS count
operator counts the number of emitted values by source observable. count
operator returns an observable that emits the count after source observable has completed its emission. On subscribe of source observable, the observable created by count
emits a single value as number which is the count of values emitted by source. The observable created by count
emits number only after source observable has emitted all its values.
Here we will discuss
count
operator in detail with examples.
RxJS count
RxJScount
operator counts the number of values emitted by source observable and emits when source emission is complete.
Find the
count
operator construct.
count(predicate?: (value: T, index: number) => boolean)
predicate is optional. We use predicate if every emission is not to be counted. Specified predicate function will decide if this emission is to be counted or not. By default all emissions are counted.
Returns
count
operator returns an observable that emits one number that represents emission count.
1.
count
operator tells how many values were emitted. The counting of emission can be controlled by passing predicate that returns boolean value. If predicate returns true, count is incremented otherwise count remains same.
2. predicate parameter has two arguments.
(value: T, index: number) => boolean
3.
count
transforms the source observable into another observable that emits a single value i.e. number of emitted values by source observable.
4. If the source observable terminates with an error,
count
will pass this error without emitting any value.
5. If source observable emission is non-ending,
count
will keep on counting but neither will emit a value not terminate.
6. If we don't pass predicate in
count
operator, then its default value is undefined and all emission by source observable will be counted. At the end of emission by source observable, total count will be emitted by count
operator
Example-1: Without Predicate
Here we will providecount
example without passing predicate. Default value is undefined. In this case count
operator will count all the values emitted by source observable and will emit count as single number after source observable completes its emission.
1. Find a simple example of
count
operator.
of("A", "B", "C", "D").pipe(count()) .subscribe(noOfEl => console.log(noOfEl)); // Output 4
count
operator will emit 4. On subscribe of source observable, we will get value emitted by observable created by count
operator. count
will emit value only when source observable has completed its emission.
2. In this example, I have a like button and I will count the clicks made by user within the 5 seconds duration.
import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core'; import { count, fromEvent, timer, takeUntil } from 'rxjs'; @Component({ selector: 'my-app', standalone: true, template: '<button #likes>Click to Like</button>' }) export class CountComponent implements AfterViewInit { @ViewChild('likes') likeMe!: ElementRef; ngAfterViewInit() { const likes$ = fromEvent(this.likeMe.nativeElement, 'click'); likes$.pipe( takeUntil(timer(5000)), count() ).subscribe(clickCount => console.log(clickCount)); } }
takeUntil
operator emits the values emitted by source observable until the specified observable to it emits a value. takeUntil(timer(5000))
will allow source observable to emit values only up to 5 seconds and after that emission is considered to be completed. count
operator will count all the clicks clicked by user within 5 seconds. It means if user has clicked 10 times on the button within 5 seconds after the application starts, the count
will emit output as 10.
Example-2: With Predicate
By passing predicate tocount
operator, we can enable it to increment count conditionally. Predicate accepts arguments as (value: T, index: number)
and returns boolean. First argument is value and second argument is index of value in emission order by source. If predicate returns true for any emitted value, count is incremented and if predicates returns false, count remains same.
1. Find a simple example with predicate.
of(15, 31, 20, 25, 17) .pipe(count((v, i) => v >= 18)) .subscribe(noOfEl => console.log(noOfEl)); // Output 3
2. Find the example of counting clicks conditionally.
ngAfterViewInit() { const likes$ = fromEvent(this.likeMe.nativeElement, 'click'); likes$.pipe( takeUntil(timer(5000)), count((v, i) => i % 2 === 0) ).subscribe(clickCount => console.log(clickCount)); }
Example-3: Never-ending Emission by Source Observable
In case of never-ending emission,count
operator will neither return a value nor terminate.
ngAfterViewInit() { const likes$ = fromEvent(this.likeMe.nativeElement, 'click'); likes$.pipe( count((value, index) => { console.log(index + 1) return true; }) ).subscribe(v => console.log(v)); }
takeUntil
. In the console, we will see output only by console.log(index + 1)
line. The line console.log(v)
will not execute.
Example-4: Error in Source Observable
If source observable throws error and does not complete emission normally,count
operator does not emit count instead pass the error thrown by source observable.
of(101, 102, 103, 104).pipe( map(v => { if(v === 103) { throw new Error('Error occurred.'); } }), count() ).subscribe(v => console.log(v))
count
on subscribe. Hence output will be ERROR Error: Error occurred in console.