RxJS - subscribe only once but do not complete Observable
Asked Answered
E

2

24

imagine situation when you have some Observable that contains data that changes in real time, example below...

interface User {
   name: string;
   projectId: string;
   dataThatChangesALotInRealTime: Object;
}

userData: Observable<User>

This userData observable is used in component to show some data that changes in real time. e.g.

<p>
{{ (userData | async)?.dataThatChangesALotInRealTime }}
</p>

Now I want to insert some data to database according to current data in userData observable. Here is the function

addToDatabase() {
  let sub = this.userData.subscribe(data => {
     this.exampleDatabase.doc(`test/${data.dataThatChangesALotInRealTime.id}`)
          .add({ test: 'hello'})
     sub.unsubscribe() // <- This
  })
}

Question

Is this a correct solution to unsubscribe inside subscription to avoid multiple insertion into database? Is there a different/better way to do this?

This is just minimalistic example, if you have some questions or my explanation is poor, let me know in comments and I will update my question. Thank you

Edina answered 9/12, 2018 at 12:56 Comment(0)
R
48

You can use the first operator:

this.userData.pipe(first()).subscribe(...);

This will automatically complete (and therefore unsubscribe) after the first value has been emitted.

Note that you should ensure that it emits at least once before completing as otherwise an error will be thrown. If you can't ensure this, you can use take(1) instead:

this.userData.pipe(take(1)).subscribe(...);

Note that this doesn't actually modify the userData observable directly, so other subscriptions to it will continue emitting regardless. This is because operators in rxjs do not modify observables but instead return a new observable.

Reboant answered 9/12, 2018 at 13:3 Comment(6)
I don't want to complete the userData observable. i still want to show data in component and maybe fire the function addToDatabase() multiple times...Edina
@Edina It doesn't stop you from doing that. The "original" observable is untouched since operators always return a new observable. So any other subscriptions to userData are unaffected by it.Frieda
If I understand correctly, whenever i use pipe operator it will creates new observable?Edina
Yes, rxjs uses immutability in this regard, so adding an operator doesn't modify the original observable but returns a new one instead.Frieda
Thank you :) Can you update your answer with this information too? It would help others, who's looking for answer.Edina
@Edina I've added it. Cheers.Frieda
C
2

Here you can use take from rxjs and give take only once (1).

like as shown below...

import { take } from 'rxjs';

this.getData().pipe(take(1)).subscribe(data => {});

Hope this will solve the issue

Happy Coding!!!

Cockahoop answered 1/12, 2022 at 8:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.