The Problem
I am using AngularFire2 and want to return the data associated with two or more contactNames.
For example querying my Realtime database for contactNames Steve and Brandon:
permits: {
1: {
permit: '12345',
contactName: 'Steve'
},
2: {
permit: '45678',
contactName: 'Brandon'
},
3: {
permit: '78910',
contactName: 'Kevin'
},
4: {
permit: '54321',
contactName: 'Steve'
},
}
Would return
1: {
permit: '12345',
contactName: 'Steve'
},
2: {
permit: '45678',
contactName: 'Brandon'
},
4: {
permit: '54321',
contactName: 'Steve'
},
My Solution Attempt
I am using map to loop through and store observables in an array
contactNamesFilter: string[] = ['Steve', 'Brandon'];
const requests = this.contactNamesFilter
.map(contactName => this.permitBrowserService.getData(contactName));
and forkJoin to join them all into one observable. (I am using RxJS v6.6.3)
forkJoin(requests).subscribe(console.log);
The problem is that subscribing to the forkJoin observable does not return anything. It appears the code is dead and is not running. I know forkJoin won't return anything until all observables have returned something. I suspect it has something to do with the permitBrowserService.getData() observable being technically the same.
What am I doing wrong? Is there a better approach to this problem?
Other Troubleshooting
I tried explicitly writing out the observable sources with the same result:
forkJoin({
sourceOne: this.permitBrowserService.getData('Steve'),
sourceTwo: this.permitBrowserService.getData('Brandon'),
}).subscribe(console.log);
Backup
I am using AngularFire2 to query the permit list:
export class PermitBrowserService {
permitData$: Observable<AngularFireAction<DataSnapshot>[]>;
contactName$: BehaviorSubject<string|null>;
constructor(
public db: AngularFireDatabase,
) {
this.contactName$ = new BehaviorSubject(null);
this.permitData$ = this.contactName$.pipe(
switchMap(contactName =>
db.list('/permits', ref =>
contactName ? ref.orderByChild('contactName').equalTo(contactName) : ref
).snapshotChanges()
)
);
}
getData(contactNameFilter?: string | null): Observable<WellPermit[]> {
if (contactNameFilter) {
this.contactName$.next(contactNameFilter);
}
return this.permitData$.pipe(
map(changes => {
return changes.map(c => {
const data = c.payload.val();
const id = c.key;
return { id, ...data };
})
})
);
}
CodePudding user response:
Since your this.permitData$
(permitBrowserService.getData()) is never going to be complete, forkJoin will never be going to emit anything. So use combineLatest, it will emit upon each this.permitData$
emit.
combineLatest({
sourceOne: this.permitBrowserService.getData('Steve'),
sourceTwo: this.permitBrowserService.getData('Brandon'),
}).subscribe(console.log);
Or
const requests = this.contactNamesFilter
.map(contactName => this.permitBrowserService.getData(contactName));
combineLatest([...requests]).subscribe(console.log);
Combines multiple Observables to create an Observable whose values are calculated from the latest values of each of its input Observables.
Accepts an Array of ObservableInput or a dictionary Object of ObservableInput and returns an Observable that emits either an array of values in the exact same order as the passed array, or a dictionary of values in the same shape as the passed dictionary.