Angular RxJS: examples cookbook

Updated: 2022-11-04

This is a collection of recipes to use declarative methods to work with data using Angular, Typescript and RxJS.

The list of examples will be improved in the future and will try to cover most of the use cases for a 'standard' application.

Create a variable in a service that can be used by multiple components

The goal is to have a variable (selectedStudent) that is stored in a service and it's accessible to other components and services of the application.

export class ExampleService { 
    // a private variable that contains the value 
private selectedStudent = new BehaviorSubject<string>(''); 
// a public method that exposes the variable as observable 
public readonly selectedStudent$ : Observable<string> = this.selectedStudent.asObservable(); 
 
// a public method that allows other components to update the local variable 
public setSelectedStudent(student: string): void { 
    this.selectedStudent.next(student); 
}} 

Filter a list using observables

Our filter is an observable and the list to filter is an observable too.

studentsFound$ = combineLatest([ 
    this.allStudents$, 
    this.nameToSearch$ 
    ]).pipe( 
        map(([students, selectedName]) => 
        students.filter(student => 
        selectedName ? student.name.includes(selectedName) : true )), 
    catchError(this.handleError) 
); 

Because we are working with 2 streams we have to combine them. When we received the 2 streams we can start to search the name of the student in the list of students.

The combineLatest will return an observable with the list of students found.

Search the details when an observable is emitted

The user choose a student from the list and we want lo search the details from the backend.

This case is particularly interesting because we are using a parameter (student.id) in a declarative method to load the data.
To use a parameter we have to emit it into the observable (in this case using selectedStudent$.

studentDetails$ = this.selectedStudent$.pipe( 
    switchMap(student =>  
    this.http.get<StudentDetail>(`${url-backend-service}/${student.id}`))) 

This method load the details from the backend every time a new observable (selectedStudent) is emitted.

You can use this method to load the details from the backend or some linked data when a new record is selected.

If we want to load related data we can use an higher-order RxJS operator (SwitchMap), this will subscribe and unsubscribe the inner observable.

The forkJoin will retrieve all the results of the multiple get as an array.

 studentLessonsDetails$ = this.selectedStudent$.pipe( 
 switchMap(student => 
    forkJoin(student.lessons.map(lesson => this.http.get<Lesson>(`${url-backend-service}/lesson/${lesson.id}`))) 
 )) 

Manage a list / cart using observables

In our case we have a cart that can contains different objects types in given quantities.

The objects can be added and removed to/from the cart using actions.

private itemSubject = new Subject<Action<ListItem>>(); 
itemAction$ = this.itemSubject.asObservable(); 
 
addToList(book: Book): void { 
    this.itemSubject.next({ 
        item: {book, 1}, 
        action: 'add' 
    }); 
} 
 
cartItems$ = this.itemAction$.pipe( 
    // scan maintains the array of cart items 
    scan((items, itemAction) => this.updateCart(items, itemAction), [] as CartItem[]) 
) 
 
private updateCart(items: CartItem[], option: Action[CartItem]): CartItem[] { 
    if('add' === option.action) { 
        return [...items, option.item] 
    } else if ('delete' === option.action) { 
        return item.filter(...) 
    } 
    return [...items]; 
} 

To maintain the array of data we can use the scan RxJS operator.


You could be interested in

Right click context menu with Angular

Right click custom menu inside dynamic lists with Angular Material
2020-05-31

Enums in Angular templates

How to use enum in the html template
2019-01-21
Fullstack Angular / Java application quick start guide.
WebApp built by Marco using SpringBoot 3.2.4 and Java 21. Hosted in Switzerland (GE8).