How can I prevent users from submitting a form multiple times? My current issue right now is when the user clicked the submit button multiple times it will create multiple users. It should create a user only once and wait before creating another user.
Here is what I have:
<button mat-flat-button color="primary" [disabled]="userStatus == 'USER_EXISTS_ON_CURRENT_ACCOUNT'" (click)="createUser()">Create
User</button>
TypeScript:
createUser() {
this.accountService.create(this.modelForm.value).pipe(
finalize(() => {
this.isInProgress = false;
})
).subscribe({next: (res) => { this.notificationService.showSuccess('User has been created successfully.');
this._router.navigate(['settings/user']);
},
error: (err) => {this.notificationService.showError('Something went wrong, Try again later.');
this.isInProgress = false;
},
complete: () => {
this.isInProgress = false;
},
});
}
CodePudding user response:
I have slightly updated your code,
1 - We will have to create a User button in the template And
<button #createUserBtn mat-flat-button color="primary" [disabled]="userStatus == 'USER_EXISTS_ON_CURRENT_ACCOUNT'"> CreateUser </button>
2 - Access Create User button in .ts file
@ViewChild('createUserBtn', {static:true}) button;
3 - Create variable clicks$
to store click events
clicks$: Observable<any>;
4 - In ngOnInit: Initialize clicks$
variable to listen click events
this.clicks$ = fromEvent(this.button.nativeElement, 'click');
5 - In ngOnInit: On every click event i.e from click$
we will pass our event to exhaustMap
The beauty of exhaustMap is once the first (outer observable) event is triggered it will stop listening to events(Outer Observable) untill it completes its inner observable
So in our case when the user clicks on the button the first time(event), the exhaustMap
will stop listening to the button click events until it completes our API call createUser()
. This API call observable we will handle using the handleResponse()
method.
ngOnInit() {
this.clicks$ = fromEvent(this.button.nativeElement, 'click');
const result$ = this.clicks$.pipe(
tap(x => console.log('clicked.')),
exhaustMap(ev => {
console.log(`processing API call`);
return this.createUser();
})
);
result$.subscribe(this.handleResponse());
}
Create User API Call
createUser(): Observable<any> {
return this.accountService.create(this.modelForm.value).pipe(
finalize(() => (this.isInProgress = false))
);
}
To handle response
handleResponse(): any {
return {
next: res => {
this.notificationService.showSuccess('User has been created successfully.');
this._router.navigate(['settings/user']);
},
error: err => {
this.notificationService.showError('Something went wrong, Try again later.');
this.isInProgress = false;
}
complete: () => this.isInProgress = false;
};
}
If you can't access button you can move ngOnit Code to AfterViewInit
Let me know if there is any error because i have not fully tested your code.
ngAfterViewInit(): void {
fromEvent(this.button.nativeElement, 'click')
.pipe(
tap(x => console.log('clicked.')),
exhaustMap(ev => {
console.log(`processing API call`);
return this.createUser();
})
)
.pipe(tap(x => console.log('Api call completed....')))
.subscribe(this.handleResponse());
}
CodePudding user response:
If the functionality you want is that the user should be restricted from clicking the button again till the API responds with a value for the prior click event, you can do the following,
In your component.html file,
<button mat-flat-button color="primary" [disabled]="isButtonDisabled()" (click)="createUser()">Create User </button>
In your component.ts file,
Create a boolean type variable, with initial value set to false.
disableUserCreation: boolean = false;
Create the following function,
isButtonDisabled(): boolean {
if (this.userStatus == 'USER_EXISTS_ON_CURRENT_ACCOUNT' || this.disableUserCreation) {
return true;
}
return false;
}
Then,
createUser() {
this.disableUserCreation = true;
this.accountService.create(this.modelForm.value).pipe(
finalize(() => {
this.isInProgress = false;
})
).subscribe({next: (res) => { this.notificationService.showSuccess('User has been created successfully.');
this._router.navigate(['settings/user']);
},
error: (err) => {this.notificationService.showError('Something went wrong, Try again later.');
this.isInProgress = false;
},
complete: () => {
this.isInProgress = false;
this.disableUserCreation = false;
},
});
}