RxJS partition operator: fork a stream like a hero

Wojciech Trawiński on 2018-12-03

There are situations when you deal with a source observable which provides data that has to be delivered to a given component based on some criteria. For example, you may have the news stream with different types of news. Since politics news may be annoying, you might decide to render them on demand (within a special component), while displaying the remaining ones within a regular component.

Partition operator

If you’re using RxJS library in your project you should make use of partition operator.

According to the docs, the operator:

“ Splits the source Observable into two, one with values that satisfy a predicate, and another with values that don’t satisfy the predicate.”

Let’s see an example in the following paragraph.

Example

https://rxjs-partition.stackblitz.io/

developers.service.ts

import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { partition } from 'rxjs/operators';

import { Developer } from './developer';

@Injectable()
export class DevelopersService {
  private developerSubject = new Subject<Developer>();
  angularDevelopers$: Observable<Developer>;
  otherDevelopers$: Observable<Developer>;

  constructor() {
    [this.angularDevelopers$, this.otherDevelopers$] = this.developerSubject.pipe(
      partition(({framework}: Developer) => framework === 'Angular')
    )
  }

  provideDeveloper(developer: Developer) {
    this.developerSubject.next(developer);
  }
}

I created the DevelopersService which enables providing new developers. Since there are Angular developers and the others :D, there is a need to split the source stream (developerSubject) into angularDevelopers$ and otherDevelopers$ streams.

As a result, you can provide a given part of the source data to a special component, while the complementing developers are rendered within a regular one.

developers-app.component.ts

import { Component } from '@angular/core';

import { DevelopersService } from './developers.service';

const getName = (function (names: string[]) {
  return () => names[Math.floor((Math.random() * names.length))];
})(['John', 'Thomas', 'Bart', 'Nico', 'Mike']);

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  angularDevelopers$ = this.developersService.angularDevelopers$;
  otherDevelopers$ = this.developersService.otherDevelopers$;

  constructor(private developersService: DevelopersService) { }

  addDev(framework: string) {

    this.developersService.provideDeveloper({
      framework,
      name: getName(),
      experience: Math.floor((Math.random() * 20))
    });
  }
}

with the following html code

developers-app.component.html

<section class="dashboard">
  <button (click)="addDev('Angular')">Add Angular Dev</button>
  <button (click)="addDev('Other')">Add Other Dev</button>
</section>

<section class="devs-dashboard">
  <section>
    <header>
      <h3>Angular</h3>
    </header>
    
    <app-developer-card *ngIf="(angularDevelopers$ | async) as dev" [developer]="dev"></app-developer-card> 
  </section>

  <section>
    <header>
      <h3>Other</h3>
    </header>
    
    <app-developer-card *ngIf="(otherDevelopers$  | async) as dev" [developer]="dev"></app-developer-card >
  </section>
</section>

Conclusions

The partition operator really rocks! If you haven’t used it yet, don’t wait any longer. I came across the operator while reading archive posts by Netanel Basal, therefore I strongly recommend following that guy.