Dart / flutter: how to build a form with multiple user input fields easily
Following Rémi's remarks, I came up with a working solution, albeit I'm pretty sure it is not the best and not to be followed on a massive scale, but should work fine for a couple of fields.
The solution comes by handling all TextField
widgets inside one single State
, alongside the e-mail composition.
In order to achieve a relatively clean code, we can use a custom function that build an input field with the appropriate data label, which accepts two input parameters: a String
and a TextEditingController
.
The label
is also used to determine which variable the setState()
method will pass the newly submitted text.
Widget buildTextInputRow(var label, TextEditingController textEditingController) { return new ListView( shrinkWrap: true, children: <Widget>[ new Row( children: <Widget>[ new Expanded( child: new Container( padding: const EdgeInsets.only(left: 5.0, top: 2.0, right: 5.0 ), child: new Text(label, style: infoText16BlackBold)), ), ], ), new Row( children: <Widget>[ new Expanded( child: new Container( padding: const EdgeInsets.only(left: 5.0, right: 5.0), child: new TextField( controller: textEditingController, decoration: new InputDecoration(hintText: adoptionHintText), onChanged: (String str) { setState(() { switch(label) { case 'Név': tempName = 'Név: ' + textEditingController.text + '\r\n'; break; case 'Kor': tempAge = 'Kor: ' + textEditingController.text + '\r\n'; break; case 'Cím': tempAddress = 'Cím: ' + textEditingController.text + '\r\n'; break; default: break; } }); } )), ), ], ) ], ); }
The problem is obviously that you will need a new TextEditingController and a new String to store every new input you want the user to enter:
TextEditingController nameInputController = new TextEditingController(); var tempName; TextEditingController ageInputController = new TextEditingController(); var tempAge; TextEditingController addressInputController = new TextEditingController(); var tempAddress;
This will result in a lot of extra lines if you have a lot of fields, and you will also have to update the composeEmail()
method accordingly, and the more fields you have, you will be more likely to forget a couple.
var emailBody; composeEmail(){ emailBody = tempName + tempAge + tempAddress; return emailBody; }
Finally, it is time to build the form:
@override Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( title: new Text('Örökbefogadás'), ), body: new ListView( children: <Widget>[ buildTextInputRow('Név', nameInputController), buildTextInputRow('Kor', ageInputController), buildTextInputRow('Cím', addressInputController), new FlatButton(onPressed: () { print(composeEmail()); }, child: new Text('test')) ], ), ); }
For convenience, I just printed the e-mail body to the console while testing
I/flutter ( 9637): Név: ZoliI/flutter ( 9637): Kor: 28I/flutter ( 9637): Cím: Budapest
All this is handled in a single State
.