Does switchMap operation work only on the first call?

I have an angular application that makes a request to an Http service and calls a switch on another Http service. For some reason, a request in switchMap only starts when the parent call is first called. Otherwise, the parent request is triggered, but switchMap is not, here is the code:

this._receivableService.newTenantDebitCredit(tenantCredit) .take(1) .switchMap(result => // Refresh the lease receivables before giving result this._receivableService.getAll({ refresh: true, where: { leaseId: this.leaseId } }).take(1).map(() => result) ) .subscribe( ... ) 

How can I make the getAll request on the switch card run every time the newTenantDebitCredit method is called on it?

Edit: here is the whole function called on click . when I press the button for the first time for this device, both methods are executed. If I try Unit, which already had a method called (without updating), only the first method is executed. I understand that a lot of this may not be entirely clear; this is a rather large project at the moment.

 public submitTenantCredit() { this.isLoading = true; let tenantCredit: NewTenantDebitCreditData; let receivableDefinitions: ReceivableDefinition[] = []; // construct receivable defintions for NewTenantDebitData model receivableDefinitions = this._constructReceivableDefinitions(); // construct data we will be POSTing to server. tenantCredit = new NewTenantDebitCreditData({ siteId: this._apiConfig.siteId, leaseId: this.leaseId, isCredit: true, receivables: receivableDefinitions, reason: this.actionReason }); // make service call and handle response this._receivableService.newTenantDebitCredit(tenantCredit) .take(1) .switchMap(result => // Refresh the lease receivables before giving result this._receivableService.getAll({ refresh: true, where: { leaseId: this.leaseId } }).take(1).map(() => result) ) .take(1) .subscribe( (receivables) => { this.closeReasonModal(); let refreshLeaseId = this.leaseId; this.leaseId = refreshLeaseId; this.isLoading = false; this.refreshBool = !this.refreshBool; this._debitCreditService.refreshUnitInfo(); this._notifications.success(`The tenant credit for ${this.customerName} - Unit ${this.unitNumber} was submitted successfully`); }, (error) => { console.error(error); this.isLoading = false; } ) } 

If this helps newTenantDebitCredit( ), this is an HTTP POST request, and getAll() is a GET request.

+5
source share
5 answers

Not quite the answer, but I solved the problem. It would almost certainly be useless to anyone, but it was a problem in the receivableService system, which was not properly plastered with boolean : refresh and pulled values ​​from the cache after the first time.

0
source

You used the take statement. When your observable service emits, take an operator that will execute first and take a chain that will only emit from the observable first. Subsequent release will not be accepted by your code. If you want all emissions to be observed, then remove them from your code.

Hope this helps.

+3
source

Testing the Rx code in isolation, here is the layout. Console logs happen every time, so I think the Rx you use is ok.

The best guess for the likely culprit is this.refreshBool = !this.refreshBool , but we need to see that the internals of newTenantDebitCredit and getAll are final.

 // Some mocking const _receivableService = { newTenantDebitCredit: (tc) => { console.log('inside newTenantDebitCredit') return Rx.Observable.of({prop1:'someValue'}) }, getAll: (options) => { console.log('inside getAll') return Rx.Observable.of({prop2:'anotherValue'}) } } const tenantCredit = {} // Test _receivableService.newTenantDebitCredit(tenantCredit) .take(1) .switchMap(result => { console.log('result', result) return _receivableService.getAll({ refresh: true, where: { leaseId: this.leaseId } }) .take(1) .map(() => result) }) .take(1) .subscribe( (receivables) => { console.log('receivables', receivables) //this.refreshBool = !this.refreshBool; }, (error) => { console.error(error); } ) 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.5.6/Rx.js"></script> 
+3
source

First of all, this has nothing to do with the switchMap operator.

Normal removal of take(1) will result in this behavior. In this case, this would not be because it is not the so-called hot observable.

The problem is that you are using http.post . This is a cold observable, which means it will only return the value once. This is also the reason you do not need to unsubscribe. He will NEVER shoot twice. Possible solutions may be:

  • Using web sockets to receive real-time data.
  • Create a timer that will periodically retrieve data.
  • Just return data when you need it.
+2
source

How do you ask a question

How can I make the getAll request on the switch card run every time the newTenantDebitCredit method is called on it?

it actually sounds to me as if you were only newTenantDebitCredit from somewhere in your code, expecting a second request to happen; therefore, I think it may be a misunderstanding of how the observed chains work. Here is an example:

 const source$ = Observable.of(42); source$ .map(value => 2 * value) .subscribe(console.log); source$ .subscribe(console.log); 

What do you expect from this? If your answer: “He will record 84 twice”, then this is not true: he records 84 and 42.

Conceptually, your situation is the same. The second request arises only when the observable returned by newTenantDebitCredit() is emitted; this will not happen at any time when the calling calls are newTenantDebitCredit . This is due to the fact that the observed chains do not mutate the observables in place, they only ever return new observables.


If you want the second request to occur, you must actually change the definition of the newTenantDebitCredit method to return the observed set to execute the second request; alternatively, set up an observable chain that you sign instead of calling newTenantDebitCredit .

+1
source

Source: https://habr.com/ru/post/1274283/


All Articles