Skip to content

Commit 9396221

Browse files
authored
Merge pull request #569 from awhitford/field_replacement_scenario
Relaxed field registration to handle field replacement scenario. Resolves #566.
2 parents 538027a + 2601353 commit 9396221

File tree

2 files changed

+34
-21
lines changed

2 files changed

+34
-21
lines changed

lib/src/form_builder.dart

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -71,49 +71,62 @@ class FormBuilder extends StatefulWidget {
7171
class FormBuilderState extends State<FormBuilder> {
7272
final _formKey = GlobalKey<FormState>();
7373

74-
Map<String, FormBuilderFieldState> _fields;
74+
final _fields = <String, FormBuilderFieldState>{};
7575

76-
Map<String, dynamic> _value;
76+
final _value = <String, dynamic>{};
7777

7878
Map<String, dynamic> get value => Map<String, dynamic>.unmodifiable(_value);
7979

8080
Map<String, dynamic> get initialValue => widget.initialValue;
8181

8282
Map<String, FormBuilderFieldState> get fields => _fields;
8383

84-
@override
85-
void initState() {
86-
super.initState();
87-
_fields = {};
88-
_value = <String, dynamic>{};
89-
}
90-
91-
@override
92-
void dispose() {
93-
_fields = null;
94-
super.dispose();
95-
}
96-
9784
void setInternalFieldValue(String name, dynamic value) {
9885
setState(() {
99-
_value = <String, dynamic>{..._value, name: value};
86+
_value[name] = value;
10087
});
10188
}
10289

10390
void removeInternalFieldValue(String name) {
10491
setState(() {
105-
_value = <String, dynamic>{..._value..remove(name)};
92+
_value.remove(name);
10693
});
10794
}
10895

10996
void registerField(String name, FormBuilderFieldState field) {
110-
assert(!_fields.containsKey(name));
97+
// Each field must have a unique name. Ideally we could simply:
98+
// assert(!_fields.containsKey(name));
99+
// However, Flutter will delay dispose of deactivated fields, so if a
100+
// field is being replaced, the new instance is registered before the old
101+
// one is unregistered. To accommodate that use case, but also provide
102+
// assistance to accidental duplicate names, we check and emit a warning.
103+
assert(() {
104+
if (_fields.containsKey(name)) {
105+
print('Warning! Replacing duplicate Field for $name'
106+
' -- this is OK to ignore as long as the field was intentionally replaced');
107+
}
108+
return true;
109+
}());
111110
_fields[name] = field;
112111
}
113112

114-
void unregisterField(String name) {
113+
void unregisterField(String name, FormBuilderFieldState field) {
115114
assert(_fields.containsKey(name));
116-
_fields.remove(name);
115+
// Only remove the field when it is the one registered. It's possible that
116+
// the field is replaced (registerField is called twice for a given name)
117+
// before unregisterField is called for the name, so just emit a warning
118+
// since it may be intentional.
119+
if (field == _fields[name]) {
120+
_fields.remove(name);
121+
} else {
122+
assert(() {
123+
// This is OK to ignore when you are intentionally replacing a field
124+
// with another field using the same name.
125+
print('Warning! Ignoring Field unregistration for $name'
126+
' -- this is OK to ignore as long as the field was intentionally replaced');
127+
return true;
128+
}());
129+
}
117130
}
118131

119132
void save() {

lib/src/form_builder_field.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ abstract class FormBuilderFieldState<F extends FormBuilderField<T>, T>
121121
if (null == widget.focusNode) {
122122
_focusNode.dispose();
123123
}
124-
_formBuilderState?.unregisterField(widget.name);
124+
_formBuilderState?.unregisterField(widget.name, this);
125125
super.dispose();
126126
}
127127

0 commit comments

Comments
 (0)