diff --git a/packages/flutter/lib/src/material/text_form_field.dart b/packages/flutter/lib/src/material/text_form_field.dart index 38f5690453..fea3d66b07 100644 --- a/packages/flutter/lib/src/material/text_form_field.dart +++ b/packages/flutter/lib/src/material/text_form_field.dart @@ -19,9 +19,15 @@ import 'theme.dart'; /// pass a [GlobalKey] to the constructor and use [GlobalKey.currentState] to /// save or reset the form field. /// -/// When a [controller] is specified, it can be used to control the text being -/// edited. Its content will be overwritten by [initialValue] (which defaults -/// to the empty string) on creation and when [reset] is called. +/// When a [controller] is specified, its [TextEditingController.text] +/// defines the [initialValue]. If this [FormField] is part of a scrolling +/// container that lazily constructs its children, like a [ListView] or a +/// [CustomScrollView], then a [controller] should be specified. +/// The controller's lifetime should be managed by a stateful widget ancestor +/// of the scrolling container. +/// +/// If a [controller] is not specified, [initialValue] can be used to give +/// the automatically generated controller an initial value. /// /// For a documentation about the various parameters, see [TextField]. /// @@ -35,16 +41,17 @@ import 'theme.dart'; class TextFormField extends FormField { /// Creates a [FormField] that contains a [TextField]. /// - /// When a [controller] is specified, it can be used to control the text - /// being edited. Its content will be overwritten by [initialValue] (which - /// defaults to the empty string) on creation and when [reset] is called. + /// When a [controller] is specified, [initialValue] must be null (the + /// default). If [controller] is null, then a [TextEditingController] + /// will be constructed automatically and its `text` will be initialized + /// to [initalValue] or the empty string. /// /// For documentation about the various parameters, see the [TextField] class /// and [new TextField], the constructor. TextFormField({ Key key, this.controller, - String initialValue: '', + String initialValue, FocusNode focusNode, InputDecoration decoration: const InputDecoration(), TextInputType keyboardType: TextInputType.text, @@ -58,7 +65,7 @@ class TextFormField extends FormField { FormFieldSetter onSaved, FormFieldValidator validator, List inputFormatters, - }) : assert(initialValue != null), + }) : assert(initialValue == null || controller == null), assert(keyboardType != null), assert(textAlign != null), assert(autofocus != null), @@ -67,7 +74,7 @@ class TextFormField extends FormField { assert(maxLines == null || maxLines > 0), super( key: key, - initialValue: initialValue, + initialValue: controller != null ? controller.text : (initialValue ?? ''), onSaved: onSaved, validator: validator, builder: (FormFieldState field) { @@ -94,7 +101,8 @@ class TextFormField extends FormField { /// Controls the text being edited. /// - /// If null, this widget will create its own [TextEditingController]. + /// If null, this widget will create its own [TextEditingController] and + /// initialize its [TextEditingController.text] with [initialValue]. final TextEditingController controller; @override @@ -115,7 +123,6 @@ class _TextFormFieldState extends FormFieldState { if (widget.controller == null) { _controller = new TextEditingController(text: widget.initialValue); } else { - widget.controller.text = widget.initialValue; widget.controller.addListener(_handleControllerChanged); } } diff --git a/packages/flutter/test/widgets/form_test.dart b/packages/flutter/test/widgets/form_test.dart index 44e81af898..4756b5c63e 100644 --- a/packages/flutter/test/widgets/form_test.dart +++ b/packages/flutter/test/widgets/form_test.dart @@ -204,8 +204,8 @@ void main() { expect(editableText.widget.controller.text, equals('world')); }); - testWidgets('Provide initial value to input when controller is specified', (WidgetTester tester) async { - final TextEditingController controller = new TextEditingController(); + testWidgets('Controller defines initial value', (WidgetTester tester) async { + final TextEditingController controller = new TextEditingController(text: 'hello'); const String initialValue = 'hello'; final GlobalKey> inputKey = new GlobalKey>(); @@ -217,7 +217,6 @@ void main() { child: new Form( child: new TextFormField( key: inputKey, - initialValue: 'hello', controller: controller, ), ), @@ -251,7 +250,6 @@ void main() { final GlobalKey formKey = new GlobalKey(); final GlobalKey> inputKey = new GlobalKey>(); final TextEditingController controller = new TextEditingController(text: 'Plover'); - const String initialValue = 'Plugh'; Widget builder() { return new Directionality( @@ -263,7 +261,7 @@ void main() { child: new TextFormField( key: inputKey, controller: controller, - initialValue: initialValue, + // initialValue is 'Plover' ), ), ), @@ -284,9 +282,9 @@ void main() { // verify value resets to initialValue on reset. formKey.currentState.reset(); await tester.idle(); - expect(inputKey.currentState.value, equals(initialValue)); - expect(editableText.widget.controller.text, equals(initialValue)); - expect(controller.text, equals(initialValue)); + expect(inputKey.currentState.value, equals('Plover')); + expect(editableText.widget.controller.text, equals('Plover')); + expect(controller.text, equals('Plover')); }); testWidgets('TextEditingController updates to/from form field value', (WidgetTester tester) async {