Skip to content

Commit aba0f42

Browse files
Te-ZRaphaelTez
authored
Auto scroll to error + Custom error (#856)
* Removed widget.decoration?.errorText * hotfix * auto scroll to error + focus on first wrongfield * custom error invalidation added * package bump * flutter 2.0 * Update * Testing * Test * Test * Flutter null safety * ios update * cleaning code * Create extension.dart * extension's export added * Update form_builder_field.dart Co-authored-by: Raphael <[email protected]> Co-authored-by: Tez <[email protected]>
1 parent ef2686b commit aba0f42

File tree

8 files changed

+100
-10
lines changed

8 files changed

+100
-10
lines changed

example/ios/Flutter/Debug.xcconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
12
#include "Generated.xcconfig"

example/ios/Flutter/Release.xcconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
#include? "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
12
#include "Generated.xcconfig"

example/ios/Podfile

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Uncomment this line to define a global platform for your project
2+
# platform :ios, '9.0'
3+
4+
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
5+
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
6+
7+
project 'Runner', {
8+
'Debug' => :debug,
9+
'Profile' => :release,
10+
'Release' => :release,
11+
}
12+
13+
def flutter_root
14+
generated_xcode_build_settings_path = File.expand_path(File.join('..', 'Flutter', 'Generated.xcconfig'), __FILE__)
15+
unless File.exist?(generated_xcode_build_settings_path)
16+
raise "#{generated_xcode_build_settings_path} must exist. If you're running pod install manually, make sure flutter pub get is executed first"
17+
end
18+
19+
File.foreach(generated_xcode_build_settings_path) do |line|
20+
matches = line.match(/FLUTTER_ROOT\=(.*)/)
21+
return matches[1].strip if matches
22+
end
23+
raise "FLUTTER_ROOT not found in #{generated_xcode_build_settings_path}. Try deleting Generated.xcconfig, then run flutter pub get"
24+
end
25+
26+
require File.expand_path(File.join('packages', 'flutter_tools', 'bin', 'podhelper'), flutter_root)
27+
28+
flutter_ios_podfile_setup
29+
30+
target 'Runner' do
31+
use_frameworks!
32+
use_modular_headers!
33+
34+
flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__))
35+
end
36+
37+
post_install do |installer|
38+
installer.pods_project.targets.each do |target|
39+
flutter_additional_ios_build_settings(target)
40+
end
41+
end

lib/flutter_form_builder.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ export './src/form_builder_field_option.dart';
2020
export './src/form_builder_validators.dart';
2121
export './src/widgets/grouped_checkbox.dart';
2222
export './src/widgets/grouped_radio.dart';
23+
export './src/utils/extension.dart';

lib/src/form_builder.dart

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,6 @@ class FormBuilderState extends State<FormBuilder> {
9494

9595
Map<String, FormBuilderFieldState> get fields => _fields;
9696

97-
/*
98-
bool get hasError => _fields.values.map((e) => e.hasError).firstWhere((element) => element == false, orElse: () => true);
99-
100-
bool get isValid => _fields.values.map((e) => e.isValid).firstWhere((element) => element == false, orElse: () => true);
101-
*/
102-
10397
void setInternalFieldValue(String name, dynamic value) {
10498
setState(() {
10599
_value[name] = value;
@@ -153,7 +147,13 @@ class FormBuilderState extends State<FormBuilder> {
153147
}
154148

155149
bool validate() {
156-
return _formKey.currentState!.validate();
150+
final validation = _formKey.currentState!.validate();
151+
if (!validation) {
152+
final wrongFields =
153+
fields.values.where((element) => element.hasError).toList();
154+
wrongFields.first.requestFocus();
155+
}
156+
return validation;
157157
}
158158

159159
bool saveAndValidate() {

lib/src/form_builder_field.dart

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ class FormBuilderField<T> extends FormField<T?> {
8383

8484
class FormBuilderFieldState<F extends FormBuilderField<T?>, T>
8585
extends FormFieldState<T?> {
86+
String? _customError;
87+
8688
@override
8789
F get widget => super.widget as F;
8890

@@ -174,15 +176,26 @@ class FormBuilderFieldState<F extends FormBuilderField<T?>, T>
174176

175177
@override
176178
bool validate() {
179+
setState(() {
180+
_customError = null;
181+
});
177182
return super.validate() && widget.decoration.errorText == null;
178183
}
179184

180185
void requestFocus() {
181186
FocusScope.of(context).requestFocus(effectiveFocusNode);
187+
Scrollable.ensureVisible(context);
188+
}
189+
190+
void invalidateField(String reason) {
191+
requestFocus();
192+
setState(() {
193+
_customError = reason;
194+
});
182195
}
183196

184197
// FIXME: This could be a getter instead of a classic function
185198
InputDecoration decoration() => widget.decoration.copyWith(
186-
errorText: widget.decoration.errorText ?? errorText,
187-
);
199+
errorText: widget.decoration.errorText ?? errorText ?? _customError,
200+
);
188201
}

lib/src/utils/extension.dart

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import 'package:flutter/widgets.dart';
2+
import 'package:flutter_form_builder/flutter_form_builder.dart';
3+
4+
extension FormKey on GlobalKey<FormBuilderState> {
5+
void invalidateField({
6+
required String name,
7+
String? reason,
8+
}) =>
9+
currentState?.fields[name]?.invalidateField(reason ?? '');
10+
11+
void invalidateFirstField({required String reason}) =>
12+
currentState?.fields.values.first.invalidateField(reason);
13+
}

pubspec.yaml

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,28 @@ dependencies:
1212
flutter_localizations:
1313
sdk: flutter
1414

15+
community_material_icon: ^5.4.55
16+
country_pickers: ^2.0.0
17+
date_range_picker: ^1.0.6
18+
datetime_picker_formfield: ^2.0.0
19+
dropdown_search: ^0.6.3
20+
file_picker: ^3.0.3
21+
flutter_colorpicker: ^0.5.0
22+
flutter_chips_input: ^1.9.5
23+
flutter_datetime_picker: ^1.4.0
24+
flutter_touch_spin: ^2.0.0-nullsafety.1
25+
flutter_typeahead: "<=1.9.1"
26+
image_picker: ^0.8.2
27+
image_picker_for_web: ^2.1.1
28+
intl: ^0.17.0
29+
permission_handler: ^8.1.3
30+
phone_number: ^0.11.0+1
31+
rating_bar: ^0.2.0
32+
signature: ^4.1.1
33+
validators: ^3.0.0
34+
35+
dependency_overrides:
1536
intl: ^0.17.0
16-
collection: ^1.15.0
1737

1838
dev_dependencies:
1939
flutter_test:

0 commit comments

Comments
 (0)