From fc870971195bcc42b98bf2916f14f2456788dd1f Mon Sep 17 00:00:00 2001 From: Ian Hickson Date: Thu, 22 Mar 2018 15:56:10 -0700 Subject: [PATCH] Add Form.onChanged, and rename FormState.onChanged (#15405) --- .../demo/material/expansion_panels_demo.dart | 8 ++--- .../lib/src/material/text_form_field.dart | 4 +-- packages/flutter/lib/src/widgets/form.dart | 35 +++++++++++++++---- 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/examples/flutter_gallery/lib/demo/material/expansion_panels_demo.dart b/examples/flutter_gallery/lib/demo/material/expansion_panels_demo.dart index 7e70319ec22..e76924428bd 100644 --- a/examples/flutter_gallery/lib/demo/material/expansion_panels_demo.dart +++ b/examples/flutter_gallery/lib/demo/material/expansion_panels_demo.dart @@ -254,7 +254,7 @@ class _ExpansionPanelsDemoState extends State { new Radio<_Location>( value: _Location.Bahamas, groupValue: field.value, - onChanged: field.onChanged, + onChanged: field.didChange, ), const Text('Bahamas') ] @@ -265,7 +265,7 @@ class _ExpansionPanelsDemoState extends State { new Radio<_Location>( value: _Location.Barbados, groupValue: field.value, - onChanged: field.onChanged, + onChanged: field.didChange, ), const Text('Barbados') ] @@ -276,7 +276,7 @@ class _ExpansionPanelsDemoState extends State { new Radio<_Location>( value: _Location.Bermuda, groupValue: field.value, - onChanged: field.onChanged, + onChanged: field.didChange, ), const Text('Bermuda') ] @@ -320,7 +320,7 @@ class _ExpansionPanelsDemoState extends State { activeColor: Colors.orange[100 + (field.value * 5.0).round()], label: '${field.value.round()}', value: field.value, - onChanged: field.onChanged, + onChanged: field.didChange, ); }, ), diff --git a/packages/flutter/lib/src/material/text_form_field.dart b/packages/flutter/lib/src/material/text_form_field.dart index 4bf60816727..f33423deaec 100644 --- a/packages/flutter/lib/src/material/text_form_field.dart +++ b/packages/flutter/lib/src/material/text_form_field.dart @@ -98,7 +98,7 @@ class TextFormField extends FormField { maxLengthEnforced: maxLengthEnforced, maxLines: maxLines, maxLength: maxLength, - onChanged: field.onChanged, + onChanged: field.didChange, onSubmitted: onFieldSubmitted, inputFormatters: inputFormatters, ); @@ -173,6 +173,6 @@ class _TextFormFieldState extends FormFieldState { // example, the reset() method. In such cases, the FormField value will // already have been set. if (_effectiveController.text != value) - onChanged(_effectiveController.text); + didChange(_effectiveController.text); } } diff --git a/packages/flutter/lib/src/widgets/form.dart b/packages/flutter/lib/src/widgets/form.dart index 602db6ffad5..709c579738a 100644 --- a/packages/flutter/lib/src/widgets/form.dart +++ b/packages/flutter/lib/src/widgets/form.dart @@ -26,6 +26,7 @@ class Form extends StatefulWidget { @required this.child, this.autovalidate: false, this.onWillPop, + this.onChanged, }) : assert(child != null), super(key: key); @@ -66,6 +67,12 @@ class Form extends StatefulWidget { /// back button. final WillPopCallback onWillPop; + /// Called when one of the form fields changes. + /// + /// In addition to this callback being invoked, all the form fields themselves + /// will rebuild. + final VoidCallback onChanged; + @override FormState createState() => new FormState(); } @@ -83,6 +90,12 @@ class FormState extends State
{ // Called when a form field has changed. This will cause all form fields // to rebuild, useful if form fields have interdependencies. void _fieldDidChange() { + if (widget.onChanged != null) + widget.onChanged(); + _forceRebuild(); + } + + void _forceRebuild() { setState(() { ++_generation; }); @@ -117,7 +130,12 @@ class FormState extends State { } /// Resets every [FormField] that is a descendant of this [Form] back to its - /// initialState. + /// [FormField.initialState]. + /// + /// The [Form.onChanged] callback will be called. + /// + /// If the form's [Form.autovalidate] property is true, the fields will all be + /// revalidated after being reset. void reset() { for (FormFieldState field in _fields) field.reset(); @@ -126,8 +144,10 @@ class FormState extends State { /// Validates every [FormField] that is a descendant of this [Form], and /// returns true if there are no errors. + /// + /// The form will rebuild to report the results. bool validate() { - _fieldDidChange(); + _forceRebuild(); return _validate(); } @@ -213,7 +233,7 @@ class FormField extends StatefulWidget { super(key: key); /// An optional method to call with the final value when the form is saved via - /// Form.save(). + /// [FormState.save]. final FormFieldSetter onSaved; /// An optional method that validates an input. Returns an error string to @@ -289,8 +309,11 @@ class FormFieldState extends State> { } /// Updates this field's state to the new value. Useful for responding to - /// child widget changes, e.g. [Slider]'s onChanged argument. - void onChanged(T value) { + /// child widget changes, e.g. [Slider]'s [Slider.onChanged] argument. + /// + /// Triggers the [Form.onChanged] callback and, if the [Form.autovalidate] + /// field is set, revalidates all the fields of the form. + void didChange(T value) { setState(() { _value = value; }); @@ -302,7 +325,7 @@ class FormFieldState extends State> { /// This method should be only be called by subclasses that need to update /// the form field value due to state changes identified during the widget /// build phase, when calling `setState` is prohibited. In all other cases, - /// the value should be set by a call to [onChanged], which ensures that + /// the value should be set by a call to [didChange], which ensures that /// `setState` is called. @protected void setValue(T value) {