Angular + RxJS : count

By Arvind Rai, 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

RxJS count 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) 
Parameters
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 
First argument is value and second argument is index of value in emission order by source observable.
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 provide count 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 
Source observable has 4 values and hence 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));
   }
} 
RxJS 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 to count 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 
Count will be incremented only if emitted value is greater or equal to 18. In the above example, output will be 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));
} 
In the above code, count will be incremented for even click only within 5 seconds. Here even clicks means ignoring first click and accepting second click then ignoring third click and accepting fourth click and so on.

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));
} 
In the above example, likes$ will never complete because I have removed 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)) 
In the above code, for the value 103, error will be thrown that will be passed by count on subscribe. Hence output will be ERROR Error: Error occurred in console.

Reference

POSTED BY
ARVIND RAI
ARVIND RAI







©2024 concretepage.com | Privacy Policy | Contact Us