This is the example of the thing i have in my angular app:
concat(
obs1$,
obs2$,
obs3$
)
.subscribe() // Output: obs1$ value, obs2$ value, obs3$ value. Basically normal concat behaviour
This is what i am trying to achieve:
concatLast(
obs1$,
obs2$,
obs3$
)
.subscribe() // Output: obs3$ value
I don't want to use skip()
, takeLast()
, switchMap()
end etc, cause it too much repeating code and doesn't look good when there will be like 5 obs. So i want to find universal solution.
Maybe there is some RxJs operator or some tricks that allows you to do such things
CodePudding user response:
You can use the last operator to filter the last item emitted by the source observable.
const { timer, concat } = rxjs;
const { mapTo, last } = rxjs.operators
const source1$ = timer(0).pipe(mapTo(1))
const source2$ = timer(50).pipe(mapTo(2))
const source3$ = timer(100).pipe(mapTo(3))
const result$ = concat(source1$, source2$, source3$).pipe(
last()
)
result$.subscribe(console.log)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/7.4.0/rxjs.umd.min.js"></script>
If you reuse this piece of code several times in your code you can avoid even more repeating code by putting this logic into a custom operator (concatLast
)
const { timer, concat } = rxjs;
const { mapTo, last } = rxjs.operators
const source1$ = timer(0).pipe(mapTo(1))
const source2$ = timer(50).pipe(mapTo(2))
const source3$ = timer(100).pipe(mapTo(3))
const concatLast = (...sources) => concat(...sources).pipe(
last()
)
const result$ = concatLast(source1$, source2$, source3$)
result$.subscribe(console.log)
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/7.4.0/rxjs.umd.min.js"></script>
CodePudding user response:
Combinelatest will emit both a
and b
every time when one of them changes. a) will emit every 10sec, and b) will emit every 3 seconds.
const a = stream('a', 10000, 10, 'partial');
const b = stream('b', 3000, 10, 'partial');
combineLatest(a, b).subscribe(fullObserver('latest'));
Example: https://stackblitz.com/edit/combine-latest-flsp5m?file=main.ts
And in Angular it could be something like this
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
mapResult: any;
from$: Subject<string> = new Subject<string>();
to$: Subject<string> = new Subject<string>();
searchTerm$ = combineLatest(this.from$, this.to$);
constructor() {}
ngOnInit() {
this.searchTerm$
.pipe(
debounceTime(1000),
switchMap((terms) => of(terms))
)
.subscribe((term: any) => (this.mapResult = term));
}
}
Example: https://stackblitz.com/edit/combinelatest-angular-army-qecyev
But using of()
is not recommended. So here is a bit newer example:
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
name = 'Angular Combine Lates With Interval Example';
subOne: BehaviorSubject<number> = new BehaviorSubject(0);
subTwo: BehaviorSubject<number> = new BehaviorSubject(0);
counterOne: number = 0;
counterTwo: number = 0;
data: [number, number];
ngOnInit() {
setInterval(() => {
this.subOne.next( this.counterOne);
}, 2000);
setInterval(() => {
this.subTwo.next( this.counterTwo);
}, 5000);
combineLatest(this.subOne, this.subTwo).subscribe((data) => {
console.log(data);
this.data = data;
});
}
}