I have a reactive form with some fields that i have subscribed to. The user enters a value on a subscribed control, tabs or clicks out of the field (blur event), a backend/http call will take place to get some additional info and fill some other fields.
This all works perfectly.
The problem arises when the user doesn't click out of the field but clicks directly on our save button that starts the logic before saving. 70 out of 100 times this also works ok, the backend call is fast enough to get the additional info and then starts the saving process but the other 30 times we are missing some info.
Off course i can do some manual checks and validators but i thought there must be a way to make sure all my valuechanges are not pending and make sure they are all completed.
Many thanks!
CodePudding user response:
You can disabled the button for the time when the API is in progress.
-Maintain a boolean variable and use the tap operator to update its
value.Internally use the switchMap
operator to make the API calls and once its is done disable the boolean value.
this.firstName.valueChanges
.pipe(
tap((x) => (this.isLoading = true)),
switchMap(() => {
return of('xxxx').pipe(delay(2000));
}),
tap((x) => (this.isLoading = false))
)
.subscribe((x) => console.log(x));
-Use the boolean variable to disable the button
<button [disabled]="isLoading">Submit</button>
In this way your button will be enabled by default however as soon as user started typing something in the textbox button will be disabled till the API response completed.
Demo:- https://stackblitz.com/edit/angular-ivy-kheete?file=src/app/app.component.ts
Note:- Delay has been added to showcase the workflow.
CodePudding user response:
It's tricky to handle If listening to valuechanges is important for your user experience instead of set a button for the user to submit his changes. You can make an out of box sloution for this senario Like:
JSON.stringify(value): To make the value easy to track it's changes.
distinictUntilChanged(): Will not emit the same value twice.
debounceTime(500): The time need to elapsed after last emit value in this example is 500ms.
JSON.parse(value): Will return the value to the original state.
this.form.valuechanges.pipe(
map(value => JSON.stringify(value),
distinictUntilChanged(),
debounceTime(500),
map(value => JSON.parse(value)))
.subscribe(value => {
...Your Code
});