DEV Community

Cover image for Rxjs Transformation and Filteration Operators
Kinanee Samson
Kinanee Samson

Posted on

Rxjs Transformation and Filteration Operators

We have familiarized ourselves with the concept of Observables. We have also looked at Subjects. Now we will focus on the different operators Rxjs comes baked with. Those operators makes working with Observables light work, and if you don't find something that get the job done for you, you can add your own operators.

Operators

An operator is just a function, there are two types of operators;

  • pipeable operators
  • creation operators

Pipeable Operators

A pipeable operator is an operator that is called within the pipe() function.

import { of } from 'rxjs'
import { filter } from 'rxjs/operators'

const evenNumbers$ = of([0,1,2,3,4,5,6,7,8,9,])
evenNumbers$.pipe(filter(num => num%2  !== 1));

evenNumbers$.subscribe(num => console.log(num))

// 0, 2, 4, 6, 8
Enter fullscreen mode Exit fullscreen mode

We used a filter operator to filter out odd numbers, and later subscribed to the Observable. The filter operator can be called inside a pipe() function, that is why they say it is a pipeable operator.
Pipeable operators return an observable. Once we subscribe to the piped operator, the also subcribe to the Observable, and we get the same insance of the observable we subscribed to.
Pipeable operators do not create Observables, they only return it. We can call the operator directly on the Observable but in practice we will use quite a number of operators, calling it on the observable is going to makenour code cluncky. So you don't Observable.filter() You do Observable.pipe(filter()) even if it's one, when we start using multiple operators you will understand why.

Creation Operators

These are standalone functions, they return a new instance of an observable when we use them so we don't bother about piping them.

import { from } from 'rxjs'
import { map } from 'rxjs/operators'

const numbers$ = from([0,1,2,3,4,5,6,7,8,9,])
numbers$.pipe(map(num => console.log(num));

numbers$.subscribe()

// 012356789
Enter fullscreen mode Exit fullscreen mode

We have so many operators so they are categorized, we have

  • Creation Operators which we just discussed above. All other categories of observables are pipeable operators

  • Transfomation Operators which we can use to modify/transfom the values emitted by the Observable

  • Filtering Operators to sort out data.

  • Join operators to help us combine higher order observables, observable of observation.

  • join creation operators

  • Conditional Operators

  • Boolean Operators

  • Multicasting Operators

  • Error Handling Operators

  • utility Operators

  • Mathemical Operators

Transformation Operators

These are functions that allow us to make some modifications to our data.

Map

Take for instance, the map() function, it works similar to the array map method. There are so many of the but I'll demo a few i use.

import { of, fromEvent } from 'rxjs'
import { map } from 'rxjs/operators'

const nums$ = of(1,2,3,4)
nums$.pipe(map(x => x + 2))

nums$.subscribe (x => console.log(x))
//  3, 4, 5,  6
// we can map to object properties

const clicks$ = fromEvent(document.body, 'click')
clicks$.pipe(map(e => e.target))

cliks$.subscribe(x => console.log(x))

Enter fullscreen mode Exit fullscreen mode

MapTo

This is similar to map but it maps all values emitted to the same value.

import { from } from 'rxjs'
import { mapTo } from 'rxjs/operators'

const nums$ = from([2, 3, 4, 5, 6, 7, 8])
nums$.pipe(mapTo(x => 0))

nums$.subscribe(console.log(x))
// 0, 0,0,0,0,0,0
Enter fullscreen mode Exit fullscreen mode

MergeMap

This function will create a map of two observables, it takes a function that we can return another Observable in. MergeMap will listen to both Observables and create a map for them.

import { from, of } from 'rxjs'
import { mergeMap } from 'rxjs/operators'

const nums$ = from([2, 3, 4])
nums$.pipe(mergeMap(x => of(`${x} value recieved`))

nums$.subscribe(console.log(x))
// 2 value recieved
// 3 value recieved
// 4 value recieved
Enter fullscreen mode Exit fullscreen mode

This operator is particularly useful when we want to make one observable wait for another one.

mergeMapTo

This operator is similar to the mergeTo operator and the mergeMap operator, it accepts a function that returns an Observable that all values emitted from an earlier Observable, the values a mapped to a particular value.

import { from, of } from 'rxjs'
import { mergeMapTo } from 'rxjs/operators'

const nums$ = from([2, 3, 4])
nums$.pipe(mergeMapTo(x => of(`a value recieved`))

nums$.subscribe(console.log(x))
// a value recieved
// a value recieved
// a value recieved
Enter fullscreen mode Exit fullscreen mode

switchMap

This operator is similar to mergeMap, but instead of mapping only once, we can return a list of maps we want. It can emit an inner Observable that accomplishes this.

import { from, of } from 'rxjs'
import { switchMap } from 'rxjs/operators'

const nums$ = from([2, 3, 4])
nums$.pipe(switcMap(x => x - 2, x + 2, x -* 2))

nums$.subscribe(console.log(x))
// 0
// 1
// 2
// 4
// 5
// 6
// 4
// 6
// 8
Enter fullscreen mode Exit fullscreen mode

This operator is useful when we want to map more than one value on the input.

Filteration Operators

These set of operators filters our data, giving us the exact matches we need

filter

This works similar to the array.filter() method, it filters the value emitted by an Observerable based on the logic jn the function we pass to it.

import { from } from 'rxjs'
import { filter } from 'rxjs/operators'

const nums$ = from([-1, 0, 1, 2, 3, 4])
nums$.pipe(
 filter(x => x > 1)
)

nums$.subscribe(x => console.log(x))
Enter fullscreen mode Exit fullscreen mode

debounce

We can use the debounce operator when we want to delay the emission of values from an Observable.

import { fromEvent, interval } from 'rxjs';
import { debounce } from 'rxjs/operators';

const clicks$ = fromEvent(document, 'mouseOver');
const result$ = clicks$.pipe(debounce(() => interval(1000)));

result$.subscribe(x => console.log(x));
Enter fullscreen mode Exit fullscreen mode

The above function will only emit the values every 1 second after we hover over the element. This function can be useful for maling search as you type feature, or a carousel.

Trottle

We can also trottle an Observable, that is emit a value first, then wait some time before emitting another value from the source observable. It is similar to debouce, the main difference is that trottle will emit a value amd then wait for our specified time before emitting the next, it will skip other values emitted by the source observable for that interval period. Debounce will wait the time given before it emits the first value aand other valuea emited by the source observable follows suit

import { from, interval } from 'rxjs';
import { trottle } from 'rxjs/operators';

const source$ = from([1,2,3,4, 5, 6, 7])
const result$ = source$.pipe(trottle(() => interval(1000)))

result.subscribe(x => console.log(x))
Enter fullscreen mode Exit fullscreen mode

first

This operator only takes the first value emitted by a source observable.

import { from } from 'rxjs';
import { first } from 'rxjs/operators';

const source$ = from([1,2,3,4]);
const result$ = source$.pipe(first());

result$.subscribe(x => console.log(x));
Enter fullscreen mode Exit fullscreen mode

find

We can also use a find operator, much like we use the array.find() method and it will return the value emitted from a source observable that meets our target.

import { fromEvent } from 'rxjs';
import { find } from 'rxjs/operators';

const source$ = fromEvent(document, 'click');
// return only the element whose id is para
const result$ = source$.pipe(find(ev => ev.target.id === 'para'));

result$.subscribe(x => console.log(x));
Enter fullscreen mode Exit fullscreen mode

take

This operator is used to trim down the number of values we recieve from a source observable, if we pass in 2 as an argument to it, it will only take the first 2 values emitted by the source observable

import { interval } from 'rxjs'
import { take } from 'rxjs/operators'

const interval$ = interval(1000)
const firstFive$ = interval$.pipe(take(5))

firstFive$.subscribe(x => console.log(x))

// output
// 0
// 1
// 2
// 3
// 4
Enter fullscreen mode Exit fullscreen mode

takeUntil

This operator is used to receieve values emitted by a source observable until a condition which is returned by another observable the takeUntil operator watches is true.

import { fromEvent, interval } from 'rxjs'
import { takeUntil } from 'rxjs/operators'

const source$ = interval(1000)
const clicks$ = fromEvent(document, 'click');

// take value emitted by the interval untill we click on the page
const result$ = source$.pipe(takeUntil(clicks$))

result$.subscribe(x => console.log(x))
Enter fullscreen mode Exit fullscreen mode

You can head to the rxjs website to learn more about these operators. I will move into using this operators to solve real problems we might encounter in our code, as we use any operator, i'll discuss about it. Hope you find this useful

Top comments (0)