Search Lessons, Code Snippets, and Videos
search by algolia
X
#native_cta# #native_desc# Sponsored by #native_company#

Top 7 RxJS Patterns for Angular Development

Episode 30 written by Jeff Delaney
full courses and content on fireship.io

RxJS, or ReactiveX for JavaScript, is notorious for its steep learning curve. Rather than try to master every aspect of it, you should focus on the concepts that will help get your app built. In this lesson, I share seven patterns that solve common issues for realtime app developers using Angular and Firebase.

1. Static vs Instance Methods

Problem: You want to use RxJS methods in Angular4.

Solution: You only import the operators you need (tree shaking) from RxJS. There are two types of RxJS operators - Static and Instance. A static method is applied to the observable class itself. This concept is important because the methods are located in difference places

  • Instance: rxjs/add/operator/{method}
  • Static: rxjs/add/observable/{method}

Here’s how we use RxJS instance method.

import { Observable } from 'rxjs/Observable';

import 'rxjs/add/operator/combineLatest';

let hello = Observable.of('Hello')
let world = Observable.of(' World')

hello.combineLatest(world)

And here’s how to use a static method:

import 'rxjs/add/observable/combineLatest';

Observable.combineLatest(hello, world)

2. Subscribe to Observable Data

Problem: You want to extract data from an observable.

Solution: You extract data by subscribing to Observables. You have two main ways of going about this in Angular. (1) Subscribe with the async pipe in the HTML or (2) subscribe manually in the TypeScript.

In this example, we use method 1 for cats and method 2 for dogs. The result is exactly the same.

cats: FirebaseListObservable<any[]>;
dogs: Array<any[]>;

ngOnInit() {

this.cats = this.db.list('/cats')

this.db.list('/dogs').subscribe(dogs => {
this.dogs = dogs
})

}

In the HTML, we unwrap cats with the async pipe, but dogs are just iterated over like a normal array.

&lt;div *ngFor=&quot;let cat of cats | async&quot;&gt;&lt;/div&gt;

&lt;div *ngFor=&quot;let dog of dogs&quot;&gt;&lt;/div&gt;

3. Unsubscribing from Observable Data

Problem: You want to prevent memory leaks by unsubscribing from observable data.

Solution: When you use the async pipe this will be handled automatically. If you created a subscription in the TypeScript, you will need to unsubscribe manually. The OnDestroy lifecycle hook is useful for ending subscriptions.

ngOnDestroy() {
this.subscription.unsubscribe()
})

4. The SwitchMap (MergeMap) Pattern

Problem: You need to extract data from observableA before you can load a related observableB.

Solution: This is a common problem with authentication. You might need to load a user, then then fetch their associated data from the database. In this example, we load the human, then load the pets that are owned by this human. We use the switchMap operator (aka mergeMap) to make this possible

human: FirebaseObjectObservable<any>;
dogs: Observable<any[]>;

ngOnInit() {

this.human = this.db.object('/humans/jeff')

this.dogs = this.human.switchMap(human => {
return this.db.list('/dogs', {
query: {
orderByChild: 'owner',
equalTo: human.name
}
})
})

}

5. Mapping Observables

Problem: You want to transform the structure of the data inside an observable.

Solution: Let’s say we want to return the length of a list observable, rather than the data itself. The map operator allows us to change convert the array into a number by returning its length. We can also take an object observable and return one of its properties a string observable.

catCount: Observable<number>;
dogName: Observable<string>;

ngOnInit() {

this.catCount = this.db.list('/cats')
.map(cats => {
return cats.length
})

this.dogName = this.db.object('/dogs/-KpRuD47u8810-BXEn5Q')
.map(dog => {
return dog.name
})

}

6. Combining Observables

Problem: You want two object observables as a single array observable.

Solution: Let add a cat and dog into their own observable using the combineLatest operator. There are many different combination operators in RxJS, so check out the docs to see what works best in your situation.

animals: Observable<any[]>

ngOnInit() {
this.cat = this.db.object('/cats/-KpRuC...Id')
this.dog = this.db.object('/dogs/-KpRuD...Id')

this.animals = Observable
.combineLatest(this.cat, this.dog)
}

7. The BehaviorSubject Pattern

Problem: You need to share current data across components or services.

A BehaviorSubject is an observable that can receive new data by calling next(data). In this example, make one of the dogs a the currentDog, then subscribe to it in the HTML.

This may seem trivial in a single component, but you can create subjects in services, then share the current state of data throughout your application by injecting the service into components.

dogs: FirebaseListObservable<any[]>;

currentDog = new BehaviorSubject(null);

ngOnInit() {
this.dogs = this.db.list('/dogs')
}

changeDog(dog) {
this.currentDog.next(dog)
}

That’s it for my Top5 RxJS concepts for Angular developers. Let me know if you have any others in the comments.