3
votes

I have to transform an object property in a RXJS Observable. This works using the "map" operator. The problem occurs when I subscribe twice to the same observable: the property is transformed twice

I have tried to use the "share" operator and multiple variations but nothing seems to work

Code Example:

    const source = of(
      { id: 1, name: 'John' },
    );

    const personObservable = source.pipe(
      map(person => { 
        person.name = person.name + '_test'; return person; 
      }),
    );

    personObservable.subscribe(
      person => console.log('first: ', person)
    );

    personObservable.subscribe(
      person => console.log('second: ', person)
    );

Expected result:

first:  John_test
second:  John_test

Actual result:

first:  John_test
second:  John_test_test
2

2 Answers

5
votes

It is because you are modifying same object instance twice. When your map would return a copy of that object it would not happen. Try this:

const personObservable = source.pipe(
      map(person => ({
          ...person,
          name: person.name + '_test'
      })),
    );

You could also use shareReplay operator with your original mapping function:

const personObservable = source.pipe(
  map(person => { 
        person.name = person.name + '_test'; return person; 
      }),
  shareReplay()
);

Stackblitz

0
votes

Another solution is to use Observable.create or new Observable() to create your Observable.

of creates a multicast Observable. new Observable will result in the creation of a cold, unicast Observable, which emits a new instance of your object for each Observer.

const source = new Observable((subscriber) => {
  subscriber.next({ id: 1, name: 'John' });
  subscriber.complete();
});

const personObservable = source.pipe(
  map(person => { 
    person.name = person.name + '_test'; return person; 
  }),
);

personObservable.subscribe(
  person => console.log('first: ', person)
);

personObservable.subscribe(
  person => console.log('second: ', person)
);

Working StackBlitz:

https://stackblitz.com/edit/angular-bdhjuo

I also recently wrote an article explaining hot and cold Observables, which you may find useful:

http://willtaylor.blog/rxjs-observables-hot-cold-explained/