If I click fast on my submit-button the form is submitted two or more times. My thought was to prevent this with the disabled attribute, but I need variable disableButon>
Dealing with double-submission is easy to do wrong. On a form with :
would only work if no validation whatsoever was present. Angular's ngForm.submitted is set to true when the button is pressed, not after the form passes validation. (NgForm's "submitted" property actually means "tried to submit".)
isn't much better: after getting validation errors on submission, the moment the user fixes the validation errors, the submit button disables itself right as they're reaching for it to re-submit.
Resetting ngForm.submitted
either directly or via ngForm.resetForm()
within your component's submit()
is a poor option, since submitted
is your primary variable controlling whether and where the validation error messages are displayed.
The real problem: Angular has no way to know when or whether your API calls in submit()
failed or succeeded. Even if Angular provided a property that meant "just clicked Submit button and it also passed all validation" on which you can hang [disabled]="thatProperty", Angular wouldn't know when to set the property back, such as when your API call errors out and you'd like to let the user press submit again to re-try the server.
Perhaps Angular might proscribe all submit functions to be of the form () => Observable
and it could subscribe to your submit's success or failure, but it seems overkill just to reset a boolean in the framework.
So you must take action after all your API calls are finished and inform Angular somehow that the submit button is ready for reuse. That action is either going to be setting the explicit boolean you are already doing, or imperatively disabling.
Here's how to do it imperatively, without the boolean.
Add a template reference variable like #submitBtn to the submit button:
Pass it to your component's submit()
:
Accept and use it component-side:
submit(submitBtn: HTMLButtonElement): void {
submitBtn.disabled = true;
/// API calls
submitBtn.disabled = false;
}
And if your API calls have multiple pathways that share a common error-handler, you'd need to pass the HTMLButtonElement on through to them as well, since they can no longer pluck it out of the component with this.disableButton
.
(Alternately, instead of declaring and passing #submitBtn, you already have #theForm declared, so pass that instead as :NgForm, and component code can drill-down to the button... or to an overlay over the whole form, or whatever.)
Whether this solution is more or less elegant than declaring another boolean that works slightly differently than ngForm.submitted
is opinion, but it is fact that Angular can't know when the component's submit() and all its async processes are finished without a subscription.