In the following code:-
RxJS.Observable.of(1,2).first().subscribe((x) => console.log(x););
is it necessary to unsubscribe given the operator first()?
No. It unsubscribes automatically after calling first(). The current syntax is observable.pipe(first()).subscribe(func); for RxJS 6.
The documentation states:
If called with no arguments, first emits the first value of the source Observable, then completes.
For the example provided, you dont need to unsubscribe, and neither you need to call first, as Observable.of(1) actually completes after emitting its first (and last) value.
first() will complete after the first item is emitted from the observable.
Also subscribe() takes three arguments, the last one being the complete callback. Running the following code will output 1 followed by 'done'.
Rx.Observable.of(1)
.subscribe(
(x) => console.log(x), // next
(x) => console.error(x), // error
() => console.log('done') // done
)
Related
how can i subscribe for example three observables, and to emit when one of them emit new value depend on the order they are, like forkJoin but emit but the order of them is important so if ob3 emit first, i want the value of obv1 to be null, also obv2
and only obv3 that was emitted will have value
for example
forkJoin(obs1,obs2,ob3)
.subscribe([ob1v,ob2v,ob3v]=>{
if (obv1v){ 'do somthing'}
if (obv2v){ 'do somthing'}
if (obv3v){ 'do somthing'}
})
thanks
Maybe combineLatest with an initial value would work for you. combineLatest will emit the latest value from each source observable whenever any of its sources emit. However, it doesn't emit for the first time until all sources have emitted at least one value.
We can use startWith to overcome this by providing an initial value for each source.
combineLatest([
obs1.pipe(startWith(null)),
obs2.pipe(startWith(null)),
obs3.pipe(startWith(null)),
])
.pipe(
skip(1) // prevent emitting initial [null, null, null] value
)
.subscribe(([v1, v2, v3]) => {
// do something here
});
You can see the output in this StackBlitz.
It seems that you want to do different thing for every observable. Maybe you shouldn't gorup them? If you want to group them and do different side effect for every one of them you can do something similar to BizzyBob anwer but instead of having if statements in subscribe use tap() operator for every stream. Something like this:
combineLatest([
obs1.pipe(tap(() => 'do somthing'),
obs2.pipe(tap(() => 'do somthing')),
obs3.pipe(tap(() => 'do somthing')),
])
.subscribe(([v1, v2, v3]) => {
});
Good practise is not to use subscribe method but instead set this stream to some property in component and than use async pipe in the template.
I would like to understand why take operator is used in code given below.
private _places = new BehaviorSubject<Place[]>(
// places for initialization
);
get places() {
return this._places.asObservable();
}
addPlace(title: string, description: string, price: number)
{
generatedId: string;
newPlace: Place;
// code to initialize newPlace
return this.http.post<{name: string}>(
'https://ionic-angular-ef2f8.firebaseio.com/offered-places.json',
{...newPlace, id: null})
.pipe(
switchMap(response => {
generatedId = response.name;
return this.places;
}),
take(1),
tap(places => {
newPlace.id = generatedId;
this._places.next(places.concat(newPlace));
})
);
}
post request returns an Observable, and we get a value from it in switchMap operator (note that we do not take a value before calling switchMap). In switchMap we replace the observable with a new observable got from _places, a BehaviourSubject object. After switchMap we use take operator.
Why don't we skip take operator, and use tap straight off? Do we take a value from an observable, because the observable is generated from a subject? Who can explain the use case of take operator in details?
UPDATE
I suspect that the reason I should use take operator after switchMap is that switchMap returns an observable received from an object of type BehaviorSubject which holds emitted values. One can subscribe to such BehaviorSubject object and take the latest emitted value - that's exactly what I did.
httpClient.post() emits one next notification and one complete notification.
However, they're using switchMap to merge another Observable to the chain (this.places). switchMap() won't complete until its source and the inner Observable complete so they're using take(1) to complete the chain after the first emission from this.places which is a BehaviorSubject that doesn't complete until you deliberately call complete() on it.
This is a very similar use-case to using takeUntil() to complete chains. takeUntil() always has to be the last operator in a chain because completing a source Observable to switchMap(), concatMap(), ... doesn't necessarily complete the whole chain. See this for more details https://medium.com/angular-in-depth/rxjs-avoiding-takeuntil-leaks-fb5182d047ef
If I have the following code:
const subject = new BehaviorSubject<[]>([]);
const observable = subject.asObservable();
subject.next([{color: 'blue'}])
observable.pipe(first()).subscribe(v => console.log(v))
According to the docs:
If called with no arguments, first emits the first value of the source Observable, then completes....
Does this mean that the source observable(the BehaviorSubject in this case) completes and you can no longer use it? As in you can no longer call .next([...]) on it.
I'm trying to understand how can an observable complete if it doesnt have the .complete() method on it?
I was trying to look at the source code of first() which under the covers uses take() and in turn take() uses lift() so I was curious if somehow first operator returns a copy of the source observable(the subject) and completes that.
The source observable is not completing, what it completes is the subscription. You could have multiple subscriptions on your Observable source, in your case one BehaviorSubject.
subject.next([{color: 'blue'}])
subject.next([{color: 'red'}])
const subs1 = observable.pipe(first()).subscribe(v => console.log(v))
const subs2 = observable.subscribe(v => console.log(v))
In the example above you clearly see that the source is not completing, just the subscription.
I have created a Stackblitz if you want to try it: https://stackblitz.com/edit/rxjs-uv6h6i
Hope I got your point!
Cheers :)
I have a side effect Observable that's required to be resolved before the main Observable is completed. If it were a synchronous operation, I could use the tap() operator. Is there a clear equivalent for an asynchronous operation?
In the following example, I have to map the inner value back to the outer value I actually want to pipe through. How would I avoid this mapping?
const user = requestUser().pipe(
switchMap(user => {
return requestAndAssignToken(user)
.pipe(
map(token => user)
);
})
);
If I understand correctly, you want to ignore the result of the inner Observable and just have the outer Observable wait for it to emit before moving on.
In that case, I'd suggest the delayWhen operator. It is passed a delayDurationSelector that returns an Observable (the duration Observable). It then behaves like stated in the documentation:
The source value is emitted on the output Observable only when the duration Observable emits a value or completes
For your example, it would look like this:
const user = requestUser().pipe(
delayWhen(user => requestAndAssignToken(user))
);
Here is a simple example
I'm trying to show a confirmation Modal, before deleting a line using RxJS.
The code below works fine if I delete 1 line.
When I delete a second line, then deleteLineFulfilled is called 2 times.
If I delete a third line, then deleteLineFulfilled is called 3 times and so on...
Any idea why?
const deleteLineEpic = (action$, store) =>
action$.ofType(DELETE_LINE_REQUEST)
.flatMap((action) => Observable.merge(
Observable.of(showModalYesNo('CONFIRM_DELETE')),
action$.ofType(MODAL_YES_CLICKED).map(() =>
deleteLineFulfilled(action.line)
)
.takeUntil(action$.ofType(MODAL_NO_CLICKED))
));
action$ is a perpetual observable, and it will only stop when an action of the type MODAL_NO_CLICKED is dispatched - from your code it's hard to say when that happens, you should add an .take(1) before the .takeUntil(...).
However with this architecture you have to make sure that there has to be either an MODAL_YES_CLICKED or MODAL_NO_CLICKED emitted and that the emission cannot be skipped.
A simpler way would be to implement the confirm-dialog, subscribe to the result and then only dispatch the delete-action if the result was YES and if the result was NO don't even dispatch the action. That way you'll have a much cleaner action-epic.
Try with this:
.first() // $action is a perpetual observable. Only take the first one.
.takeUntil(action$.ofType(MODAL_NO_CLICKED))