Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RXJS Observable remove pipe operators

Tags:

I have a problem where I want to remove/add any previous added operators of an observable.

I am given the following observable which I cannot change:

let objects$ = of([{
      category: 1,
      name: 'Some1'
    }, {
      category: 2,
      name: 'Some2'
    }]).pipe(
      map(o => o.filter(b => b.category === 2))
    )
    objects$.subscribe(obj => console.log(obj));

This outputs: {category: 2,name: 'Some2'} as expected.

Now I want to change the value of the filter to b.category === 1 to output {category: 1,name: 'Some1'}.

If I do the following:

objects$.pipe(
      map(o => o.filter(b => b.category === 1))
    )
    objects$.subscribe(obj => console.log(obj));

I still get {category: 2,name: 'Some2'}.

If I do:

objects$ = objects$.pipe(
      map(o => o.filter(b => b.category === 1))
    )
    objects$.subscribe(obj => console.log(obj));

I get [] because the output of the observable does not have category 1 anymore.

The question I have is how do I remove the .pipe() from the original observable to add a new one ?

like image 613
Luke Kroon Avatar asked Nov 14 '19 11:11

Luke Kroon


People also ask

Does pipe subscribe to an Observable?

The async pipe subscribes to an Observable or Promise and returns the latest value it has emitted.

How do you remove an object from Observable?

To trigger an element deletion, simply send an event on the subject: this. deleteSubject. next({op:'delete', id: '1'});

How do I stop nested observables?

To avoid nested subscribe calls you can always map back from a meta branch, such as a stream that has been forked from the main branch through some AJAX call or some other async operation, to a trunk branch by using mergeMap .

Does pipe return Observable?

The pipe() function takes one or more operators and returns an RxJS Observable. pipe can be used as a standalone method, which helps Angular developers reuse it at multiple places or as an instance method. This article will explain what pipe is and how to use it in an Angular Application.


2 Answers

You can't remove operators

By using pipe e.g. calling observable$.pipe( map(..) ) you're not really adding something to the observable$ that can be taken away later on, even if the phrase add operator X to your observable is quiet often used.

A pipeable Operator is a function that takes an Observable as its input and returns another Observable. It is a pure operation: the previous Observable stays unmodified

const o1$ = of('1');
const o2$ = o1$.pipe(
  map(x => x + '2'),
  map(x => x + '3')
);

is equivalent to

const o1$ = of('1');
const o2$ = map(x => x + '3')(
  map(x => x + '2')(
    o1$
  )
);

You're basically chaining pure function calls with your original Observable o1$ as input and some other Observable as output. o1$ won't be changed so you have to assign the returned value to a variable (o2$) to use later on or use it directly to have any effect.

In the example above you could reuse o1$ and create a different Observable than o2$ by using different operators on o1$. You can't however remove the function calls that are used to define o2$ from o2$.

You should be able to change implementation specifics you care

If you're given an Observable you cannot change you shouldn't be concerned with it's specific implementation but only with what it emits. In this case the Observable is a black box to you and as far as you know just emits { category: 2, name: 'Some2' }. You don't know and shouldn't care about specific things the Observable did along the way to emit this value.

BUT you seem to know and care about what the Observable did before emitting this value. If you do, there has to be a way for you (or a colleague) to change the implementation of the Observable.

Inject code dynamically

If you have code where one part should be fixed and another part should be dynamic you can define a higher order function (fixed part) that accepts another function (dynamic part) as input and create different Observables from one original Observable this way:

let getObjects$ = (predicate: (value: any) => boolean) => of([
  {
    category: 1,
    name: "Some1"
  },
  {
    category: 2,
    name: "Some2"
  }
]).pipe(map(o => o.filter(predicate)));

getObjects$(v => v.category === 1).subscribe(obj => console.log(obj));
getObjects$(v => v.category === 2).subscribe(obj => console.log(obj));
like image 106
frido Avatar answered Jan 02 '23 10:01

frido


You are applying pipe operator in the first operation (objects$ => Observable.pipe()). After first operation, objects$ inner value will be:

[{category: 2,name: 'Some2'}]

Then your second operation will be done on the result of first one(Observable.pipe(...).pipe(...)). It will not change the value of objects$. But you're again subscribing the initial observable (objects$ => Observable.pipe()). The second pipe will not mutate the value, instead returns new Observable after applying pipe operator function.

For the desired result:

let objects$ = of([
  {
    category: 1,
    name: "Some1"
  },
  {
    category: 2,
    name: "Some2"
  }
]);

objects$
  .pipe(map(o => o.filter(b => b.category === 1)))
  .subscribe(obj => console.log(obj));

objects$
  .pipe(map(o => o.filter(b => b.category === 2)))
  .subscribe(obj => console.log(obj));
like image 36
Jins Thomas Shaji Avatar answered Jan 02 '23 12:01

Jins Thomas Shaji