Problem: I have am trying to implement logic to reload page data. When calling an API to reload a user party, if they are a creditor, I need to call another API to load their bank details. Currently, after reading this and other related posts, I get the concept and need to avoid nested subscriptions, but I am unsure how to refactor my code to abide by best practices. I am essentially trying to chain subscriptions to two APIs.
*Using rxjs 6.6.2
Parent Method that calls reload data
reloadData(partyId) {
if(!!partyId) {
this.pageData = new PartyPageData();
this.reloadPartyDetails(partyId);
this.getSupportingCurrencies();
}
}
Method to reload party details
reloadPartyDetails(partyId) {
this.receiverService.getPartyDetails(partyId).pipe(
take(1),
map(response => response.body)
).subscribe(response => {
this.pageData.party = response;
this.pageData.action = CONSTANTS.PARTY.ACTION.UPDATE;
if(this.pageData?.party?.side?.toUpperCase() == CONSTANTS.PARTY.PARTY_SIDE.CREDITOR.toUpperCase()) {
this.pageData.partySide = CONSTANTS.PARTY.PARTY_SIDE.RECEIVER;
this.reloadBankDetails(partyId);
}
else {
this.pageData.partySide = CONSTANTS.PARTY.PARTY_SIDE.SENDER;
}
this.changeDetector.detectChanges();
}, error => {
this.goBack();
});
}
Nested method to reload bank details
reloadBankDetails(partyId) {
this.receiverService.getAllPartyBankAccounts(partyId).pipe(
take(1),
map(response => response.body)
).subscribe(response => {
if(!this.pageData?.bank) {
this.pageData.bank = new BankDetails(CONSTANTS.PARTY.PARTY_SIDE.CREDITOR);
this.pageData.bank.financialInstitution = new FinancialInstitution;
}
this.pageData.bank.accountName = response?.[0].accountName,
this.pageData.bank.accountNumber = response?.[0].accountNumber;
this.pageData.bank.currencyCode = response?.[0].currencyCode;
this.pageData.bank.preferredFlag = response?.[0].preferred;
this.pageData.bank.type = response?.[0].accountType;
this.pageData.bank.memberId = response?.[0].financialInstitution.memberId;
this.pageData.bank.financialInstitution = this.setFinanicalInstitution(response?.[0].financialInstitution);
this.pageData.bank.accountId = response?.[0].accountId;
this.pageData.bank.reEnterAccountNumber = response?.[0].accountNumber;
this.changeDetector.detectChanges();
}, error => {
this.goBack();
});
}
I feel as though I am missing a core concept. Perhaps regarding mapping or observables and how to handle them.
I looked at rxjs concat()
and concatMap()
but i am not sure if/how to use them, or to refactor my code so that i can use them.
When looking at other solutions that refactor to maps, i am unsure how properties get implicitly assigned to their target values. e.g. how in the linked page this.seller
and this.rating
get assigned.
I tried to refactor the reloadPartyDetails to look more like:
reloadPartyDetails(partyId) {
this.receiverService.getPartyDetails(partyId).pipe(
take(1),
map(response => response.body),
mergeMap(response => { // or switchMap() or flatMap()?
this.pageData.party = response;
this.pageData.action = CONSTANTS.PARTY.ACTION.UPDATE;
if(this.pageData?.party?.side?.toUpperCase() == CONSTANTS.PARTY.PARTY_SIDE.CREDITOR.toUpperCase()) {
this.pageData.partySide = CONSTANTS.PARTY.PARTY_SIDE.RECEIVER;
return this.pageData.partySide;
}
else {
this.pageData.partySide = CONSTANTS.PARTY.PARTY_SIDE.SENDER;
}
this.changeDetector.detectChanges();
})).subscribe(partySide => {
this.reloadBankDetails(partyId);
});
}
this example made sense, but I did not understand how to refactor it if the .subscribe()
was not empty, as in my case.
But I am not sure how to maintain the internal functionality of reloadBankDetails() I am also not sure whether switchMap(), mergeMap(), flatMap(), or concat() is the appopriate higher order observable mapping method to use.
There is only one nested subscription, that should get called conditionally. But re-writing it this way seems to just perpetuate nested subscriptions.