
INTRODUTION
I’ve studied RxJS from a lot of resources and I’ve had a lot of difficulty finding real examples of applying it in user interfaces (except in forms).
In this article I simply tried to exploit the reactive programming paradigm and some RxJS operators to manage all the behaviors of an image gallery built in Angular and Typescript.
Of course, the ways of achieving the same result are endless and this is just an “exercise in style”.
Also, I want to point out that this exercise does not really demonstrate the potential of RxJS. Only applying and chaining more operators and Observable you can really understand the powerful of this amazing approach.
ASSETS
The first step is the creation of a file (./assets.ts
) to contains the collection of photos we would like to show in the gallery:
export const PHOTOS = [ 'http://lorempixel.com/400/200/animals/1', 'http://lorempixel.com/400/200/animals/2', 'http://lorempixel.com/400/200/business/3', 'http://lorempixel.com/400/200/sports/1', ];
CODE
The view is very simple and it’s composed by a couple of buttons (PREV and NEXT), an image element and a text to display the counter value.
import { Component, EventEmitter } from '@angular/core'; import { Subject, Observable } from 'rxjs'; import { PHOTOS } from './assets'; @Component({ selector: 'app-component', template: ` <img src="{{photos[(counter$ | async)]}}"> <h1>#{{(counter$ | async)+1}}</h1> <button (click)="button$.next(-1)">Prev</button> <button (click)="button$.next(1)">Next</button> ` }) export class AppComponent { photos = PHOTOS; START = 0; TOTAL = PHOTOS.length; button$ = new Subject(); counter$: Observable<any>; constructor() { this.counter$ = Observable.merge( this.button$, Observable.interval(5000).mapTo(1) ) .startWith(this.START) .scan((acc: number, curr: any) => { // if next && last image if (curr === 1 && acc === this.TOTAL - 1) return 0; // if prev && first image if (curr === -1 && acc === 0) return this.TOTAL - 1; // all other cases return acc + curr; }) } }
KEY POINTS
buttons$
is aSubject
, a special Observable you can use as observer and observable.
So, in this scenario, it can be used to increase the counter (aka publish) and, at the same time, we can subscribe it.- The counter will be increased or decreased when buttons are clicked by invoking the
next()
method and passing+1
or-1
. counter$
is an Observable used to mergebuttons$
with another Observable, an interval that emits a+1
value every 5 seconds.scan
is an RxJS operator used to calculate the next counter value applying an accumulator function (adding the current value to the accumulated one). It’s very similar to the concept ofreduce
.- Every 5000ms the
interval
emits a value that is mapped to+1
by using themapTo
operator with the purpose to simulate the click of the NEXT button. By passing a value of-1
the gallery would show the previous image after each interval. async
is a special Angular pipe to automatically subscribe an Observable and returns the latest emitted value
NOTE
In a real-world scenario you would probably move all this code in a custom component, i.e. GalleryComponent
, whose assets will be retrieved by a server-side request and passed as input property.
Leave A Comment