I'll show you the working code first:
<input [formControl]="search"
[typeahead]="suggestions"
typeaheadOptionField="name"
(typeaheadOnSelect)="onSelectedDriver($event)">
ngOnInit(){
public autocompleteValue() {
this.search.valueChanges.subscribe(
(selectedValue) => {
this.searchVal(selectedValue)
}
);
}
}
public searchVal(val: string) {
this.suggestions = (new Observable((observer: Observer<string>) => {
observer.next(val);
})).pipe(
switchMap((query: string) => {
if (query) {
switch (this.serverApi) {
case 'Driver':
return this.getAllDrivers(query);
default:
break;
}
}
return of([]);
})
);
}
and:
getAllDrivers(query: string) {
return this.accountsService.getDrivers(query)
.pipe(
map((data: any) => {
data.body?.forEach((driver: IDriver) => {
driver.name = `${driver.firstName} ${driver.lastName}`
});
return data.body || [];
}),
tap(() => noop, err => {
this.errorMessage = err && err.message || 'Something goes wrong';
})
)
}
This works.
But i need to expand functionality.
I need an extension to merge two api calls into one and return the result.
I am to do it but without typeahead with forkJoin..
this.search.valueChanges.subscribe(val => {
let driverLoad = this.service.searchDrivers(val, [{ name: 'name', value: val }]);
let affiliateLoad = this.service.searchAffiliates(val, [{ name: 'name', value: val }])
forkJoin([driverLoad, affiliateLoad, travelAgenciesLoad]).subscribe(resultsOfSearch => {
let driverArr = resultsOfSearch[0].body;
let affiliateArr = resultsOfSearch[1].body;
this.autoCompleteResults = [...driverArr as [], ...affiliateArr as []];
return this.autoCompleteResults
})
});
I don't know now to fit this to work.
How do I combine this and return the result?
CodePudding user response:
forkJoin
forkJoin only emits a value when all source observables have completed. Because of this - it may not be suitable for your situation.
Wait for Observables to complete and then combine last values they emitted; complete immediately if an empty array is passed.
In your code, forkJoin will not emit a value until the observables driverLoad, affiliateLoad, and travelAgenciesLoad have all completed.
combineLatest
If your three Observables are continuous data streams that need to be combined before they complete, a better operator is combineLatest:
Whenever any input Observable emits a value, it computes a formula using the latest values from all the inputs, then emits the output of that formula.
//Define observables before subscribing to valueChanges
let driverLoad = this.service.searchDrivers(val, [{ name: 'name', value: val }]);
let affiliateLoad = this.service.searchAffiliates(val, [{ name: 'name', value: val }])
let combinationObservable$: Observable<any>;
// when valueChanges emits a value, find the latest emitted value from driverLoad,
// affiliateLoad, and travelAgenciesLoad
this.search.valueChanges.subscribe(val => {
combinationObservable$ = combineLatest([driverLoad, affiliateLoad, travelAgenciesLoad]);
}
//subscribe to combination Observable outside of the valueChanges subscription
combinationObservable$.subscribe(value => {
console.log(value);
this.autoCompleteResults = value;
});
Here is a StackBlitz I made to simulate your observables with the combineLatest operator.
CodePudding user response:
You can use rxjs zip (After all observables emit, it will emit values as an array) thus you can get the result in an array directly
import { zip } from 'rxjs';
let driverLoad = this.service.searchDrivers(val, [{ name: 'name', value: val }]).pipe(map(data => data.body));
let affiliateLoad = this.service.searchAffiliates(val, [{ name: 'name', value: val }]).pipe(map(data => data.body))
zip(driverLoad , affiliateLoad).subscribe((results: any[]) => console.log(results) )