Rxjs Transformation and Filteration Operators
Tags: javascript, webdev
Published: 2021-03-21 08:04:30

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. 
```javascript
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
```

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. 


```javascript
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
```
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.

```javascript
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))

```

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

```javascript
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
```

### 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.

```javascript
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
```
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.

```javascript
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
```

### 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.

```javascript
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
```
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.

```javascript
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))
```

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

```javascript
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));
```
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

```javascript
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))
```

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

```javascript
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));
```

### 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.

```javascript
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));
```

### 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

```javascript
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
```

### 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. 

```javascript
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))
```
You can head to the [rxjs](rxjs-dev.firebase.app) 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