@@ -241,11 +241,13 @@ export class FormState<T, State = DefaultState, Error extends string = DefaultEr
241
241
* @param notifyParent Should this form notify the parent form about this change?
242
242
*/
243
243
public setValues ( values : T , validate ?: boolean , isDefault : boolean = false , notifyChild : boolean = true , notifyParent : boolean = true ) {
244
+ // No set is used because this could cause problems with array keys, which must always be in the right order
244
245
let keys = Object . keys ( isDefault ? this . defaultValues : this . values ) ;
245
246
let newKeys = Object . keys ( values ) ;
246
247
for ( let i = 0 ; i < newKeys . length ; i ++ ) {
247
248
if ( ! keys . includes ( newKeys [ i ] ) ) keys . push ( newKeys [ i ] ) ;
248
249
}
250
+
249
251
// Traverse backwards, so when removing array items, the whole array gets shifted in the right direction
250
252
for ( let i = keys . length - 1 ; i >= 0 ; i -- ) {
251
253
let key = keys [ i ] as keyof T ;
@@ -409,6 +411,34 @@ export class FormState<T, State = DefaultState, Error extends string = DefaultEr
409
411
if ( notifyParent ) this . updateParentState ( ) ;
410
412
}
411
413
414
+ /**
415
+ * Creates a submit handler to pass to your `<form onSubmit={...}>`. The function executes the passed handler only if the form validates correctly.
416
+ * @param handler The handler to execute when this form contains no errors.
417
+ */
418
+ public handleSubmit ( handler : ( form : FormState < T , State , Error > ) => void | Promise < void > ) {
419
+ async function handle ( this : FormState < T , State , Error > , ev : React . FormEvent < HTMLFormElement > ) {
420
+ ev . preventDefault ( ) ;
421
+
422
+ // Show helpful warning when using buttons to submit
423
+ if ( process . env . NODE_ENV === "development" ) {
424
+ let buttons = Array . from ( ( ev . target as HTMLFormElement ) . querySelectorAll ( "button" ) ) ;
425
+ let noTypeButton = buttons . find ( ( e ) => ! ( "type" in e . attributes ) ) ;
426
+ if ( noTypeButton ) {
427
+ console . error (
428
+ `The submitted form contains a button without a type attribute. Please populate every button in your form with either type="button" or type="submit".` ,
429
+ noTypeButton
430
+ ) ;
431
+ }
432
+ }
433
+
434
+ if ( ! ( await this . validate ( ) ) ) return ;
435
+ this . setState ( { ...this . state , isSubmitting : true } ) ;
436
+ await handler ( this ) ;
437
+ this . setState ( { ...this . state , isSubmitting : false } ) ;
438
+ }
439
+ return handle . bind ( this ) ;
440
+ }
441
+
412
442
/**
413
443
* Listen for changes on a field, will trigger when value, defaultValue, dirty and error changes for a field. Make sure you pass its return value back to `ignore()` after you are done listening.
414
444
* @param key The field to listen to.
0 commit comments