Skip to main content

Basic ObservablePipes

ObservablePipes are the most important bricks to build complex data flow with our Observables.

In this tutorial, we'll learn how to use some of the essentials ObservablePipes provided by @lirx/core.

Filtering and mapping

The most common pipes are filter$$$, map$$$, and distinct$$$.

For example, we may want to filter only even numbers, and then cast them to string:

const subscribe = pipe$$(single(0, 1, 2, 3, 4, 5), [
filter$$$(v => v % 2 === 0),

subscribe((value: string) => {

As you may have already noted, this is quite similar to the and Array.filter functions:

const data = [0, 1, 2, 3, 4, 5]
.filter(v => v % 2 === 0)


However, it works with streams of data instead of static values.

Debouncing values

Sometimes, we need to delay incoming values and/or discard next values during a period.

The most common pipes are debounceTime$$$ and throttleTime$$$.

As an example, this is especially useful when we want to debounce user's click:

const subscribe = pipe$$(fromEventTarget(window, 'click'), [

subscribe(() => {

When an Observable emits a value, map this value and return another Observable

One of the most used pipe is switchMap$$$. It maps the incoming values of an Observable to another one.

It allows us to listen to an element's size selected by a user click for example:

const subscribe = pipe$$(fromEventTarget(window, 'click'), [
// maps incoming event to the "select" element using
map$$$((event: MouseEvent): HTMLElement => as HTMLElement),
// maps incoming element into an Observable listening to its size
switchMap$$$((element: HTMLElement): IObservable<DOMRectReadOnly> => {
// use merge to get the initial size, and the new size if the element is resized
return merge([
// initial size
reference((): DOMRectReadOnly => element.getBoundingClientRect()),
// listen to the element's size and map the value to get a DOMRectReadOnly
map$$(fromResizeObserver(, ({ contentRect }) => contentRect),

subscribe(({ width, height }) => {
console.log(width, height);

However, it is a little more complex than the previous one. So don't hesitate to play with it.

Sharing values of an Observable (only subscribing once)

As a final example, another common use case: if we want to subscribe many times to an Observable but subscribe only once to the original one, we may use shareRL$$$.

const subscribe = pipe$$(interval(1000), [
scan$$$<void, number>(count => (count + 1), 0),

subscribe((value: number) => {
console.log('value - A:', value);

// note that interval(1000) is only subscribed once
subscribe((value: number) => {
console.log('value - B:', value);

Going deeper

Plenty of others ObservablePipes may be found on the reference page.

They are some of the most powerful tools in this library. However, it requires you to browse carefully through the documentation. Some of these pipes are pretty complex to understand, do not hesitate to play with them, and take time to check the examples. Finally, everytime you're facing a problem and want to implement your own ObservablePipe, or if you're forced to perform some ugly trick, there is probably an ObservablePipe already existing and documented. In this situation take a look at the decision tree page.