Pattern Intoduction to Rxjs

Recently, we upgraded our mobile app from Ionic 1 to Ionic 5. 

Wrapping our head around Angular, after working for so long in angular js, wasn't too big of a hurdle.

The problem with Rxjs - it's difficult to find examples of how to do stuff.

Take for example, infinite scroll.

What is infinite scroll?

When the user opens the page showing the rows of data - you will load up the first 10 rows.

When the user has scrolled near the end of the page, you can check if a new page is there and if yes, make an api call to fetch the next page and append it to the end of the pre existing list.

And not just vanilla infinite scroll, it was chocolate cake infinite scroll with cherry on top- 

  • Infinite scroll to be present as default
  • Filters and sorting can be applied from the UI
  • When search is used, all of the data is to be pulled in (so that we can filter everything by text)
  • On pull to refresh, invalidate the cache and reload data

We had our work cut out for us and doing it the right way was very necessary since this is used in very critical pages.

With Rxjs - things started to feel easier once we got around learning how to think about them. 

This blog won't contain any tutorials for Rxjs but make you familiar with two design patterns which will help you understand what is going on when you start working with rxjs.

What are design patterns?

Design patterns are meta structures that you use when approaching a very specific kind of problem.

The examples I have presented here are in typescript, but you can transfer them to pretty much any other language.

The two patterns you must know - 

  • Observer
  • Iterator

The Observer Pattern

An Observer pattern is where you have an Observable where you observe something and call a method called notify as an event occurs.

All the update methods in the Observers associated with the Observable are called whenever the notify is triggered by the Observable.

The pattern classes- 

interface Observer {

  update(e: any): void;

}

abstract class Subject {

  observers: Observer[] = [];

  attach(ob: Observer) {

    this.observers.push(ob);

  }

  notify(e) {

    this.observers.forEach(observer => {

      observer.update(e);

    });

  }

}

Concrete implementations - 

class LoggerObserver implements Observer {

  update(e) {

    console.log('logger', e);

  }

}

class DoubleLoggerObserver implements Observer {

  update(e) {

    console.log('double logger', e);

    console.log('double logger', e);

  }

}

Usage - 

const inputElement: HTMLElement = document.getElementById("sample");

class FormInputSubject extends Subject {

  constructor(el: HTMLElement) {

    super();

    el.addEventListener("keydown", event => {

      this.notify(event);

    });

  }

}

const formObservable = new FormInputObservable(inputElement);

formObservable.attach(new DoubleLoggerObserver());

formObservable.attach(new LoggerObserver());

If you look at the usage - you will see that FormInputObservable does not contain any code regarding what happens when the event occurs

This is exactly what the Observer pattern does -
it helps decouple an event from what is to happen when the event occurs.

Working Sample - https://stackblitz.com/edit/typescript-tzqqqk?file=index.ts

The Iterator Design Pattern

The iterator pattern is used to traverse a collection, where the underlying data structure may be anything ( an array, tree etc ).

Say you have a tree data structure. 

You can traverse this in many ways - depth first, breadth first etc

Having an uniform way to traverse this is what the iterator pattern provides you.

interface AIterator<T> {

  // Return the current element.

  current(): T;

  // Return the current element and move forward to the next element.

  next(): T;

  // Return the key of the current element.

  key(): number;

}

The concrete implementation - 

class NumberArrayIterator implements AIterator<number> {

  arr: number[];

  currentIndex: number;

  constructor(arr: number[]) {

    this.arr = arr;

    this.currentIndex = -1;

  }

 next(): number {

    if (this.arr[this.currentIndex + 1]) {

      this.currentIndex = this.currentIndex + 1;

      return this.arr[this.currentIndex];

    }

    return null;

  }

  current(): number {

    return this.arr[this.currentIndex];

  }

  key(): number {

    return this.currentIndex;

  }

}

const a = new NumberArrayIterator([1, 2, 3, 4, 5]);

while (a.next()) {

  console.log(a.current());

}

The iterator pattern is awesome in the sense that you can think of anything you want to iterate on and model it in this format.

Working Sample - https://stackblitz.com/edit/typescript-6cbbbc?file=index.ts

Now, back to Rxjs.

Rxjs is based around something called an Observable. 

An Observable in Rxjs is basically a combination of the Observer and Iterator.

To create an Observable

const ob$ = new Observable(subscriber => {
    subscriber.next(1);

    subscriber.next(2);

    subscriber.next(3);

    subscriber.next(4);

   // it doesn't matter if this set interval goes on forever. An observer stops emitting once it has     completed

    setInterval(()=> {
          subscriber.next(2);

     subscriber.next(3);

     subscriber.next(4);
    }, 100);

   setTimeout(()=> {

     subscriber.complete();   
  });
});

const sub1 =  ob$.pipe(

  filter(x => x/2)

).subscribe(val => {
  console.log(‘first’, val);
});

const sub2 = ob$.subscribe(val => {
  console.log(‘second’, val);

  console.log(‘second’, val);
});

Like the Observer design pattern - an Observable decouples the creation of the events from how you would handle them.

And it allows you to process the events that would come from this observable in the form of a stream - similar to the iterator pattern.

The subscribe is nothing but a for Each on events that arrive over time till the iterator reaches its end or the subscription is stopped manually.

This gives rise to a very powerful pattern that you can use the stream of events that arrive over time and mould them using operators - similar to how you use map, filter and reduce on arrays.

 For a in depth study, I would highly recommend
- https://springframework.guru/gang-of-four-design-patterns/

 - https://refactoring.guru/design-patterns/

Aiyush Dhar

I am a Member of Technical Staff at Fyle. Beyond work, I find solace in video games, blogging, and my hot cup of ginger lemon tea.

More of our stories from

Engineering
How we used AMP Emails to get feedback on AMP Emails!

This blog discusses the how's & why's behind us building a feedback & monitoring system for AMP Emails using AMP Emails

Read more...
Pattern Intoduction to Rxjs

Make yourself familiar with two design patterns which will help you understand what is going on when you start working with rxjs.

Read more...
How we created a Medium-like blurry background effect

Here's how we improved user experience, decreased load time and made Fyle accessible for users without a fast internet.

Read more...
Bye bye WordPress, welcome Webflow.

This blogpost documents our journey as we bid goodbye to WordPress and migrated to Webflow.

Read more...
How we reduced our website build time by 59%

I came up with five 3 second changes to reduce the build time by over 59%. Here's more about my experience.

Read more...
Hello, Web Technologies!

I’m a first-time entrepreneur and I’ll be recording my learnings and experiments over time. I am always eager to interac

Read more...
The Non-Boring Guide to OAuth 2.0

If you’re developing an application that needs access to a user’s Google / Facebook / LinkedIn information, you’ll need

Read more...
Dealing with Nested Objects in your Web Application

A couple of weeks ago, I ran into a peculiar problem that I think might be useful to talk about. It took me a bunch of

Read more...
Eliminate Boilerplate Java code with Lombok

I’ve been writing a lot of boilerplate Java code, lately — getters, setters, hashCode, equals and toString. Actually, I’

Read more...

All Topics