Create an image Gallery using Angular and RxJS

Home/code/angular/Create an image Gallery using Angular and RxJS

Create an image Gallery using Angular and RxJS

A simple image gallery built in Angular by using RxJS operators and Subject


LIVE DEMO

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 a Subject, 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 merge buttons$ 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 of reduce.
  • Every 5000ms the interval emits a value that is mapped to +1 by using the mapTo 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.

2017-07-17T00:58:28+00:00 luglio 11th, 2017|angular|

Leave A Comment