From 1f5ad3e2b327437b75a8e06772c2139b6803286a Mon Sep 17 00:00:00 2001 From: GChanathip Date: Sun, 6 Apr 2025 15:21:45 +0700 Subject: [PATCH 1/3] add patchError --- lib/src/form_builder.dart | 66 +++++++++++++-------------------------- 1 file changed, 21 insertions(+), 45 deletions(-) diff --git a/lib/src/form_builder.dart b/lib/src/form_builder.dart index f5ce4239a..3c19c6041 100644 --- a/lib/src/form_builder.dart +++ b/lib/src/form_builder.dart @@ -110,16 +110,14 @@ class FormBuilder extends StatefulWidget { this.canPop, }); - static FormBuilderState? of(BuildContext context) => - context.findAncestorStateOfType(); + static FormBuilderState? of(BuildContext context) => context.findAncestorStateOfType(); @override FormBuilderState createState() => FormBuilderState(); } /// A type alias for a map of form fields. -typedef FormBuilderFields = - Map, dynamic>>; +typedef FormBuilderFields = Map, dynamic>>; class FormBuilderState extends State { final GlobalKey _formKey = GlobalKey(); @@ -153,9 +151,7 @@ class FormBuilderState extends State { /// Get a map of errors Map get errors => { - for (var element in fields.entries.where( - (element) => element.value.hasError, - )) + for (var element in fields.entries.where((element) => element.value.hasError)) element.key.toString(): element.value.errorText ?? '', }; @@ -167,22 +163,12 @@ class FormBuilderState extends State { /// Get all fields values of form. Map get instantValue => Map.unmodifiable( - _instantValue.map( - (key, value) => MapEntry( - key, - _transformers[key] == null ? value : _transformers[key]!(value), - ), - ), + _instantValue.map((key, value) => MapEntry(key, _transformers[key] == null ? value : _transformers[key]!(value))), ); /// Returns the saved value only Map get value => Map.unmodifiable( - _savedValue.map( - (key, value) => MapEntry( - key, - _transformers[key] == null ? value : _transformers[key]!(value), - ), - ), + _savedValue.map((key, value) => MapEntry(key, _transformers[key] == null ? value : _transformers[key]!(value))), ); dynamic transformValue(String name, T? v) { @@ -195,8 +181,7 @@ class FormBuilderState extends State { } T? getRawValue(String name, {bool fromSaved = false}) { - return (fromSaved ? _savedValue[name] : _instantValue[name]) ?? - initialValue[name]; + return (fromSaved ? _savedValue[name] : _instantValue[name]) ?? initialValue[name]; } /// Get a field value by name @@ -290,15 +275,11 @@ class FormBuilderState extends State { /// the form will auto scroll to show this invalid field. /// In this case, the automatic scroll happens because is a behavior inside the framework, /// not because [autoScrollWhenFocusOnInvalid] is `true`. - bool validate({ - bool focusOnInvalid = true, - bool autoScrollWhenFocusOnInvalid = false, - }) { + bool validate({bool focusOnInvalid = true, bool autoScrollWhenFocusOnInvalid = false}) { _focusOnInvalid = focusOnInvalid; final hasError = !_formKey.currentState!.validate(); if (hasError) { - final wrongFields = - fields.values.where((element) => element.hasError).toList(); + final wrongFields = fields.values.where((element) => element.hasError).toList(); if (wrongFields.isNotEmpty) { if (focusOnInvalid) { wrongFields.first.focus(); @@ -323,15 +304,9 @@ class FormBuilderState extends State { /// the form will auto scroll to show this invalid field. /// In this case, the automatic scroll happens because is a behavior inside the framework, /// not because [autoScrollWhenFocusOnInvalid] is `true`. - bool saveAndValidate({ - bool focusOnInvalid = true, - bool autoScrollWhenFocusOnInvalid = false, - }) { + bool saveAndValidate({bool focusOnInvalid = true, bool autoScrollWhenFocusOnInvalid = false}) { save(); - return validate( - focusOnInvalid: focusOnInvalid, - autoScrollWhenFocusOnInvalid: autoScrollWhenFocusOnInvalid, - ); + return validate(focusOnInvalid: focusOnInvalid, autoScrollWhenFocusOnInvalid: autoScrollWhenFocusOnInvalid); } /// Reset form to `initialValue` set on FormBuilder or on each field. @@ -349,6 +324,14 @@ class FormBuilderState extends State { }); } + /// Update fields errors of form. + /// Useful when need update errors at once, after got errors from server. + void patchError(Map errors) { + errors.forEach((key, value) { + _fields[key]?.invalidate(value); + }); + } + @override void initState() { // Verify if need auto validate form @@ -369,19 +352,13 @@ class FormBuilderState extends State { onPopInvokedWithResult: widget.onPopInvokedWithResult, canPop: widget.canPop, // `onChanged` is called during setInternalFieldValue else will be called early - child: _FormBuilderScope( - formState: this, - child: FocusTraversalGroup(child: widget.child), - ), + child: _FormBuilderScope(formState: this, child: FocusTraversalGroup(child: widget.child)), ); } } class _FormBuilderScope extends InheritedWidget { - const _FormBuilderScope({ - required super.child, - required FormBuilderState formState, - }) : _formState = formState; + const _FormBuilderScope({required super.child, required FormBuilderState formState}) : _formState = formState; final FormBuilderState _formState; @@ -389,6 +366,5 @@ class _FormBuilderScope extends InheritedWidget { FormBuilder get form => _formState.widget; @override - bool updateShouldNotify(_FormBuilderScope oldWidget) => - oldWidget._formState != _formState; + bool updateShouldNotify(_FormBuilderScope oldWidget) => oldWidget._formState != _formState; } From 58297e8ff696e5949981667b544cfa315526052e Mon Sep 17 00:00:00 2001 From: GChanathip Date: Sun, 6 Apr 2025 15:36:59 +0700 Subject: [PATCH 2/3] extract scrollToFirstInvalidField as a function and add to patchErros --- lib/src/form_builder.dart | 52 +++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/lib/src/form_builder.dart b/lib/src/form_builder.dart index 3c19c6041..9dbc0d955 100644 --- a/lib/src/form_builder.dart +++ b/lib/src/form_builder.dart @@ -279,15 +279,10 @@ class FormBuilderState extends State { _focusOnInvalid = focusOnInvalid; final hasError = !_formKey.currentState!.validate(); if (hasError) { - final wrongFields = fields.values.where((element) => element.hasError).toList(); - if (wrongFields.isNotEmpty) { - if (focusOnInvalid) { - wrongFields.first.focus(); - } - if (autoScrollWhenFocusOnInvalid) { - wrongFields.first.ensureScrollableVisibility(); - } - } + scrollToFirstInvalidField( + focusOnInvalid: focusOnInvalid, + autoScrollWhenFocusOnInvalid: autoScrollWhenFocusOnInvalid, + ); } return !hasError; } @@ -326,10 +321,47 @@ class FormBuilderState extends State { /// Update fields errors of form. /// Useful when need update errors at once, after got errors from server. - void patchError(Map errors) { + /// + /// Focus to first invalid field when has field invalid, if [focusOnInvalid] is `true`. + /// By default `true` + /// + /// Auto scroll to first invalid field focused if [autoScrollWhenFocusOnInvalid] is `true`. + /// By default `false`. + /// + /// Note: If a invalid field is from type **TextField** and will focused, + /// the form will auto scroll to show this invalid field. + /// In this case, the automatic scroll happens because is a behavior inside the framework, + /// not because [autoScrollWhenFocusOnInvalid] is `true`. + void patchError(Map errors, {bool focusOnInvalid = true, bool autoScrollWhenFocusOnInvalid = false}) { errors.forEach((key, value) { _fields[key]?.invalidate(value); }); + scrollToFirstInvalidField( + focusOnInvalid: focusOnInvalid, + autoScrollWhenFocusOnInvalid: autoScrollWhenFocusOnInvalid, + ); + } + + /// Focus to first invalid field when has field invalid, if [focusOnInvalid] is `true`. + /// By default `true` + /// + /// Auto scroll to first invalid field focused if [autoScrollWhenFocusOnInvalid] is `true`. + /// By default `false`. + /// + /// Note: If a invalid field is from type **TextField** and will focused, + /// the form will auto scroll to show this invalid field. + /// In this case, the automatic scroll happens because is a behavior inside the framework, + /// not because [autoScrollWhenFocusOnInvalid] is `true`. + void scrollToFirstInvalidField({bool focusOnInvalid = true, bool autoScrollWhenFocusOnInvalid = false}) { + final wrongFields = fields.values.where((element) => element.hasError).toList(); + if (wrongFields.isNotEmpty) { + if (focusOnInvalid) { + wrongFields.first.focus(); + } + if (autoScrollWhenFocusOnInvalid) { + wrongFields.first.ensureScrollableVisibility(); + } + } } @override From 2d6fe1e3ac6eadc74b8c2290d446887a855f3657 Mon Sep 17 00:00:00 2001 From: GChanathip Date: Sun, 6 Apr 2025 15:44:43 +0700 Subject: [PATCH 3/3] fomat length --- lib/src/form_builder.dart | 69 ++++++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 15 deletions(-) diff --git a/lib/src/form_builder.dart b/lib/src/form_builder.dart index 9dbc0d955..617530d9b 100644 --- a/lib/src/form_builder.dart +++ b/lib/src/form_builder.dart @@ -110,14 +110,16 @@ class FormBuilder extends StatefulWidget { this.canPop, }); - static FormBuilderState? of(BuildContext context) => context.findAncestorStateOfType(); + static FormBuilderState? of(BuildContext context) => + context.findAncestorStateOfType(); @override FormBuilderState createState() => FormBuilderState(); } /// A type alias for a map of form fields. -typedef FormBuilderFields = Map, dynamic>>; +typedef FormBuilderFields = + Map, dynamic>>; class FormBuilderState extends State { final GlobalKey _formKey = GlobalKey(); @@ -151,7 +153,9 @@ class FormBuilderState extends State { /// Get a map of errors Map get errors => { - for (var element in fields.entries.where((element) => element.value.hasError)) + for (var element in fields.entries.where( + (element) => element.value.hasError, + )) element.key.toString(): element.value.errorText ?? '', }; @@ -163,12 +167,22 @@ class FormBuilderState extends State { /// Get all fields values of form. Map get instantValue => Map.unmodifiable( - _instantValue.map((key, value) => MapEntry(key, _transformers[key] == null ? value : _transformers[key]!(value))), + _instantValue.map( + (key, value) => MapEntry( + key, + _transformers[key] == null ? value : _transformers[key]!(value), + ), + ), ); /// Returns the saved value only Map get value => Map.unmodifiable( - _savedValue.map((key, value) => MapEntry(key, _transformers[key] == null ? value : _transformers[key]!(value))), + _savedValue.map( + (key, value) => MapEntry( + key, + _transformers[key] == null ? value : _transformers[key]!(value), + ), + ), ); dynamic transformValue(String name, T? v) { @@ -181,7 +195,8 @@ class FormBuilderState extends State { } T? getRawValue(String name, {bool fromSaved = false}) { - return (fromSaved ? _savedValue[name] : _instantValue[name]) ?? initialValue[name]; + return (fromSaved ? _savedValue[name] : _instantValue[name]) ?? + initialValue[name]; } /// Get a field value by name @@ -275,7 +290,10 @@ class FormBuilderState extends State { /// the form will auto scroll to show this invalid field. /// In this case, the automatic scroll happens because is a behavior inside the framework, /// not because [autoScrollWhenFocusOnInvalid] is `true`. - bool validate({bool focusOnInvalid = true, bool autoScrollWhenFocusOnInvalid = false}) { + bool validate({ + bool focusOnInvalid = true, + bool autoScrollWhenFocusOnInvalid = false, + }) { _focusOnInvalid = focusOnInvalid; final hasError = !_formKey.currentState!.validate(); if (hasError) { @@ -299,9 +317,15 @@ class FormBuilderState extends State { /// the form will auto scroll to show this invalid field. /// In this case, the automatic scroll happens because is a behavior inside the framework, /// not because [autoScrollWhenFocusOnInvalid] is `true`. - bool saveAndValidate({bool focusOnInvalid = true, bool autoScrollWhenFocusOnInvalid = false}) { + bool saveAndValidate({ + bool focusOnInvalid = true, + bool autoScrollWhenFocusOnInvalid = false, + }) { save(); - return validate(focusOnInvalid: focusOnInvalid, autoScrollWhenFocusOnInvalid: autoScrollWhenFocusOnInvalid); + return validate( + focusOnInvalid: focusOnInvalid, + autoScrollWhenFocusOnInvalid: autoScrollWhenFocusOnInvalid, + ); } /// Reset form to `initialValue` set on FormBuilder or on each field. @@ -332,7 +356,11 @@ class FormBuilderState extends State { /// the form will auto scroll to show this invalid field. /// In this case, the automatic scroll happens because is a behavior inside the framework, /// not because [autoScrollWhenFocusOnInvalid] is `true`. - void patchError(Map errors, {bool focusOnInvalid = true, bool autoScrollWhenFocusOnInvalid = false}) { + void patchError( + Map errors, { + bool focusOnInvalid = true, + bool autoScrollWhenFocusOnInvalid = false, + }) { errors.forEach((key, value) { _fields[key]?.invalidate(value); }); @@ -352,8 +380,12 @@ class FormBuilderState extends State { /// the form will auto scroll to show this invalid field. /// In this case, the automatic scroll happens because is a behavior inside the framework, /// not because [autoScrollWhenFocusOnInvalid] is `true`. - void scrollToFirstInvalidField({bool focusOnInvalid = true, bool autoScrollWhenFocusOnInvalid = false}) { - final wrongFields = fields.values.where((element) => element.hasError).toList(); + void scrollToFirstInvalidField({ + bool focusOnInvalid = true, + bool autoScrollWhenFocusOnInvalid = false, + }) { + final wrongFields = + fields.values.where((element) => element.hasError).toList(); if (wrongFields.isNotEmpty) { if (focusOnInvalid) { wrongFields.first.focus(); @@ -384,13 +416,19 @@ class FormBuilderState extends State { onPopInvokedWithResult: widget.onPopInvokedWithResult, canPop: widget.canPop, // `onChanged` is called during setInternalFieldValue else will be called early - child: _FormBuilderScope(formState: this, child: FocusTraversalGroup(child: widget.child)), + child: _FormBuilderScope( + formState: this, + child: FocusTraversalGroup(child: widget.child), + ), ); } } class _FormBuilderScope extends InheritedWidget { - const _FormBuilderScope({required super.child, required FormBuilderState formState}) : _formState = formState; + const _FormBuilderScope({ + required super.child, + required FormBuilderState formState, + }) : _formState = formState; final FormBuilderState _formState; @@ -398,5 +436,6 @@ class _FormBuilderScope extends InheritedWidget { FormBuilder get form => _formState.widget; @override - bool updateShouldNotify(_FormBuilderScope oldWidget) => oldWidget._formState != _formState; + bool updateShouldNotify(_FormBuilderScope oldWidget) => + oldWidget._formState != _formState; }