I have a only one question
I begin learn a flutter in yesterday.
How to get a Textfield value ?
I tried call a TextEditingController anybody in a class.
But It's not working to.
[![enter image description here][1]][1]
class LoginScreen extends StatefulWidget {
#override
_LoginState createState() => _LoginState();
}
class _LoginState extends State<LoginScreen> {
final userId = TextEditingController();
final userPass = TextEditingController();
...TextInputField(),
PasswordInput(),
LoginButton()
}
void loginAct() async {
var data = {
"user_id": userId, //undefined
"user_pass": userPass, //undefined
};
class TextInputField extends StatelessWidget {
const TextInputField({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: Container(
height: size.height * 0.08,
width: size.width * 0.8,
decoration: BoxDecoration(
color: Colors.grey[500],
borderRadius: BorderRadius.circular(16),
),
child: TextField(
controller: userId, <=== (The getter 'userId' isn't defined for the class 'TextInputField')
decoration: InputDecoration(
border: InputBorder.none,
prefixIcon: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Icon(
FontAwesomeIcons.user,
size: 28,
color: Colors.black54,
),
),
hintText: 'id',
),
),
),
);
}
}
how to resolve that?
if flutter you can get text field value by different methods
by text editing controller
add this on top
final userNameController = TextEditingController();
final passwordController = TextEditingController();
then on text field
TextField(
controller: userNameController,
);
TextField(
controller: passwordController,
);
and on function pass the value as you like
onPressed: () => loginAct(userNameController.text,passwordController.text),
in this case you need to specify what is initial value through controller
for Second Question
http.get(Uri.https('https://swapi.co', 'api/people'));
or
http.get(Uri.parse('https://swapi.co/api/people'));
try this on your code
class TextInputField extends StatelessWidget {
const TextInputField({ Key? key }) : super(key: key);
#override
Widget build(BuildContext context) {
final userIdController = TextEditingController();
final passwordController = TextEditingController();
return Container(
child: TextField(
controller: userId,
onpressed: () {loginAct(password:passwordController.text,userName:userIdController.
text)})
);
}
your login function
void loginAct({String password, String userName}) async {
var data = {
"user_id": password,
"user_pass": userName,
}
Related
I want to make my flutter project highly manageable, apply clean code and maintain DRY concept strictly. There are a lot of input elements in any flutter project. So I want to make this element as a separate widget so that if I want to change in future then I will change in one place. Here is my approach:
import 'package:flutter/material.dart';
import '../utility/validatation.dart';
class RegistrationPage extends StatefulWidget {
static const String routeName = '/registrationPage';
#override
State<RegistrationPage> createState() => _RegistrationPageState();
}
class _RegistrationPageState extends State<RegistrationPage> {
final _formKey = GlobalKey<FormState>();
final TextEditingController nameInput = TextEditingController();
final TextEditingController businessName = TextEditingController();
final TextEditingController productTypeId = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: new Form(
key: _formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
Container(
height: 70,
margin: EdgeInsets.only(bottom: 50),
child: Image(image: AssetImage('assets/logo.png')),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 10, horizontal: 30.0),
child: TextInput(inputController: nameInput, label: 'আপনার নাম'),
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_register(context);
}
},
child: Text('Next'),
)
]),
),
);
}
void _register(BuildContext context) {}
}
class TextInput extends StatelessWidget {
const TextInput({
Key? key,
required this.inputController,
required this.label,
}) : super(key: key);
final TextEditingController inputController;
final String label;
#override
Widget build(BuildContext context) {
return TextFormField(
controller: inputController,
keyboardType: TextInputType.text,
decoration: const InputDecoration(
border: UnderlineInputBorder(),
prefixIcon: Icon(Icons.phone),
labelText: label,
),
validator: (value) {
return Validation.required(value);
},
);
}
}
But I got this error:
What is wrong in my code? Is there any problem in my approach or should I stop thinking to refactor my code as I do? Please also suggest if there is any smarter way to make code more clean and manageable.
Oh I see so you have this
class TextInput extends StatelessWidget {
const TextInput({
Key? key,
required this.inputController,
required this.label,
}) : super(key: key);
final TextEditingController inputController;
final String label;
#override
Widget build(BuildContext context) {
return TextFormField(
controller: inputController,
keyboardType: TextInputType.text,
// Notice the const here right?
// So the idea is that decoration objects could rebuild to either change one thing or the other, so 'label' here cannot be a constant
//So to solve this InputDecoration should not have const.
decoration: const InputDecoration(
border: UnderlineInputBorder(),
prefixIcon: Icon(Icons.phone),
labelText: label,
),
validator: (value) {
return Validation.required(value);
},
);
}
}
Since you are using a variable in InputDecoration, you should not declare InputDecoration with const keyword.
I am making an app where a user can add multiple stateful widgets in a list view inside a home stateful widget.
Example: list of ingredients.
Every ingredient widget has a TextFormField.
A user can add as many ingredients as wish to and eventually the data entered will be updated using a POST request from the home stateful widget.
Question: How do i access the TextFormField controller of every added ingredient widget from the home state.
Also is this the best way to approcah this or is there a better way?
class home extends StatefulWidget {
const home({Key? key}) : super(key: key);
#override
_homeState createState() => _homeState();
}
class _homeState extends State<home> {
List<Widget> listRecipe = [];
addIngredient(){
listRecipe.add(new Ingredient());
}
Future<http.Response> postData(){
return http.post(
Uri.parse(recipeData),
headers: <String, String>{
'Authorization':'token $token',
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
"name":"something",
"ingredients":'{"ingredient1": "value", "ingredient2": "value", ...... }'
}),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Container(
child: Wrap(
children:[ ListView(
children:listRecipe,
),
],
),
),
] ),
bottomNavigationBar: Row(
children:
[FloatingActionButton(
onPressed: addIngredient,
),
FloatingActionButton(onPressed: postData)
]));
}
}
class Ingredient extends StatefulWidget {
const Ingredient({Key? key}) : super(key: key);
#override
_IngredientState createState() => _IngredientState();
}
class _IngredientState extends State<Ingredient> {
final _typeController = TextEditingController();
#override
Widget build(BuildContext context) {
return Container(
child: Padding(
padding: EdgeInsets.only(left: 22, top: 20, right: 15),
child: Column(
children: [
Container(
width: MediaQuery.of(context).size.width,
child: Padding(
padding: const EdgeInsets.only(left: 5.0),
child: Text(
"Process",
style: TextStyle(
fontFamily: 'Nunito',
color: Colors.grey.shade500,
fontSize: 12,
),
textAlign: TextAlign.left,
),
),
),
Container(
height: 45,
child: TextFormField(
keyboardType: TextInputType.text,
maxLines: null,
controller: _typeController,
style: TextStyle(fontSize: 15, fontFamily: 'Nunito'),
decoration: InputDecoration(
hintText: 'Enter Process',
hintStyle: TextStyle(color: Colors.grey.shade400),
contentPadding: EdgeInsets.only(left: 5),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.green)),
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.green, width: 2),
),
),
),
),
],
),
),
);;
}
}
tl:dr
Add final String property to your StatefulWidget
in initState assign value of property to TextEditingController:
textEditingController.text = widget.stringValue
override didUpdateWidget and also set TextEditingControllerValue textEditingController.text = widget.stringValue
I would suggest to add a model for your Ingredient, e.g:
class Ingredient {
String? data;
Ingredient({this.data});
}
Rename the Ingredient Widget to e.g. IngredientWidget. The type of your listReceipe should stay List<Ingredient>:
List<Ingredient> listRecipe = [];
addIngredient() {
setState(() {
listRecipe.add(Ingredient());
});
}
Change the body of your Home Widget:
body: Container(
child: ListView.builder(
itemCount: listRecipe.length,
itemBuilder: (context, index) =>
IngredientWidget(listRecipe[index]))),
Now change your IngredientWidget like this:
class IngredientWidget extends StatefulWidget {
const IngredientWidget(this.ingredient, {Key? key}) : super(key: key);
final Ingredient ingredient;
#override
_IngredientWidgetState createState() => _IngredientWidgetState();
}
class _IngredientWidgetState extends State<IngredientWidget> {
final _typeController = TextEditingController();
#override
void didUpdateWidget(covariant IngredientWidget oldWidget) {
super.didUpdateWidget(oldWidget);
_typeController.text = widget.ingredient.data ?? '';
}
#override
void initState() {
super.initState();
_typeController.text = widget.ingredient.data ?? '';
}
#override
Widget build(BuildContext context) {
// stays the same
}
}
You can pass a Value to your Ingredient widget:
Ingredient(data: 'Hello World')
So you can also update an Ingredient in listReceipe with
setState(() {
listRecipe[index] = Ingredient(data: anyStringValue);
});
and your list should update accordingly.
questionController.text always returns me a null value. rather than Whatever I insert in textformfield.
class _AddQuestionState extends State<AddQuestion> {
TextEditingController questionController = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
TextFormField(
controller: questionController,
decoration: InputDecoration(
hintText: 'description',
hintStyle: TextStyle(
color: Colors.grey
),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0)),
),
),),
AddUser(questionController.text),]
}}
When I called this class and print the output, it returns me null.
Using AddUser(questionController.text);
I printed the output using print(question) but it returns me empty string.
class AddUser extends StatelessWidget {
final String question;
AddUser(this.question);
#override
Widget build(BuildContext context) {
// Create a CollectionReference called users that references the firestore collection
CollectionReference users = FirebaseFirestore.instance.collection('Questions').doc("cse").collection("CSE");
Future<void> addUser() {
print(question);
// Call the user's CollectionReference to add a new user
return users
.add({
'question': question, // John Doe
})
.then((value) => print("User Added"))
.catchError((error) => print("Failed to add user: $error"));
}
What happen is when it first build the screen your AddQuestion widget questionController is set to empty string which is passed to the AddUser() widget.
If [controller] is null, then a [TextEditingController] will be constructed automatically and its text will be initialized to [initialValue] or the empty string.
When you changed the value in your questionController, your AddUser() widget didnt know the changes. By adding setState it will rebuild the whole AddQuestion widget and passed the new value to your AddUser widget.
Try this example to have an undestanding
class MyWidget extends StatefulWidget {
const MyWidget({Key? key}) : super(key: key);
#override
State<MyWidget> createState() => _MyWidgetState();
}
class _MyWidgetState extends State<MyWidget> {
TextEditingController questionController = TextEditingController();
String? questionValue;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
children: [
TextFormField(
controller: questionController,
decoration: InputDecoration(
hintText: 'description',
hintStyle: TextStyle(color: Colors.grey),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(20.0)),
),
),
),
SizedBox(height: 20),
TextButton(
onPressed: () {
print("questionController: ${questionController.text}");
setState(() {
questionValue = questionController.text;
});
},
child: Text("SETSTATE BUTTON"),
),
SizedBox(height: 20),
Text("questionValue: $questionValue"),
SizedBox(height: 20),
AddUser(questionController.text),
],
),
),
);
}
}
class AddUser extends StatelessWidget {
final String question;
AddUser(this.question);
#override
Widget build(BuildContext context) {
return Text("question: $question");
}
}
I'm developing a app with a register, login and reset password screen. In all this screens the user must enter his e-mail address. Now i will not implement the e-mail address textfield for every single screen. So i will implement a email textfield widget for every screen like the code below.
import 'package:flutter/material.dart';
import 'package:email_validator/email_validator.dart';
class EMailTextFormField extends StatefulWidget {
#override
_EMailTextFormFieldState createState() => _EMailTextFormFieldState();
}
class _EMailTextFormFieldState extends State<EMailTextFormField> {
final _email = TextEditingController();
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 3.0),
child: TextFormField(
decoration: InputDecoration(
icon: Icon(Icons.email, size: IconTheme.of(context).size, color: IconTheme.of(context).color),
labelText: 'E-Mail...',
counterText: '',
),
keyboardType: TextInputType.emailAddress,
controller: _email,
validator: _validateEmail,
maxLength: 70,
),
);
}
String _validateEmail(String email) {
// validate E-Mail function...
}
}
My problem is now that i can't use the TextEditingController (_email) outside this widget in the different screens (register, login and reset password) like this as a example:
final FirebaseUser user = (await _auth.createUserWithEmailAndPassword(
email: _email.text.toString(), password: _password.text.toString())).user;
The error is "Undefined name _email" because the _email TextEditingController is in the EMailTextFormField widget, but how can i give the value of the _email field from EMailTextFormField widget to the other screens (register, login and reset password)?
Can anyone help me i found so far no solution.
You can do this using onSaved callback.
EMailTextFormField:
class EMailTextFormField extends StatefulWidget {
final void Function(String email) onSaved;
const EMailTextFormField({Key key, this.onSaved}) : super(key: key);
#override
EMailTextFormFieldState createState() => EMailTextFormFieldState();
}
class EMailTextFormFieldState extends State<EMailTextFormField> {
final _email = TextEditingController();
#override
Widget build(BuildContext context) {
return Container(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 3.0),
child: TextFormField(
decoration: InputDecoration(
icon: Icon(Icons.email, size: IconTheme.of(context).size, color: IconTheme.of(context).color),
labelText: 'E-Mail...',
counterText: '',
),
keyboardType: TextInputType.emailAddress,
controller: _email,
validator: _validateEmail,
maxLength: 70,
onSaved: widget.onSaved, //callback
),
);
}
String _validateEmail(String email) {
// validate E-Mail function...
}
}
Page where you will use EMailTextFormField:
class EmailPage extends StatefulWidget {
EmailPage({Key key}) : super(key: key);
#override
_EmailPageState createState() => _EmailPageState();
}
class _EmailPageState extends State<EmailPage> {
String _email;
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Email Page'),
),
body: Form(
key: _formKey,
child: Column(
children: <Widget>[
EMailTextFormField(
onSaved: (String email) => _email = email,
),
RaisedButton(
child: Text('Go'),
onPressed: (){
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
print(_email);
}
},
)
],
),
),
);
}
}
i have a form which i decided to break into multiple widget for code re- usability. the problem i am having i dont know how to interact with each components. for example, if the main form declare a variable, how do i access that variable in the custom textfield widget which is store in a different dart file.
below is the code i have
form dart file (main.dart)
import 'package:flutter/material.dart';
import 'package:finsec/widget/row_text_input.dart';
import 'package:finsec/widget/text_form_field.dart';
import 'package:finsec/widget/save_button.dart';
import 'package:finsec/utils/strings.dart';
import 'package:finsec/utils/dimens.dart';
import 'package:finsec/utils/colors.dart';
import 'package:finsec/widget/column_text_input.dart';
void main() {
runApp(MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Simple Interest Calculator App',
home: ThirdFragment(),
theme: ThemeData(
brightness: Brightness.dark,
primaryColor: Colors.indigo,
accentColor: Colors.indigoAccent),
));
}
class ThirdFragment extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _ThirdFragmentState();
}
}
class _ThirdFragmentState extends State<ThirdFragment> {
var _formKey = GlobalKey<FormState>();
var _currentItemSelected = '';
bool isError = false;
bool isButtonPressed = false;
#override
void initState() {
super.initState();
}
TextEditingController amountController = TextEditingController();
TextEditingController frequencyController = TextEditingController();
#override
Widget build(BuildContext context) {
TextStyle textStyle = Theme.of(context).textTheme.title;
return Scaffold(
appBar: AppBar(
title: Text('Simple Interest Calculator'),
),
body: Form(
key: _formKey,
child: SingleChildScrollView(
child: Column (children: [
Padding(
padding: EdgeInsets.only(top: 10.0, bottom: 5.0, left: 15.0, right: 15.0),
child: CustomTextField(textInputType:TextInputType.number,
textController: amountController,
errorMessage:'Enter Income Amount',
labelText:'Income Amount for testing'),
),
RowTextInput(inputName: 'Frequency:',
textInputType: TextInputType.number,
textController: frequencyController,
errorMessage: 'Choose Income Frequency',
labelText: 'Income Amount for testing'
),
RowTextInput(inputName: 'Date Paid:',
textInputType: TextInputType.number,
textController: datePaidController,
errorMessage: 'Pick Income Payment Date',
labelText: 'Income Amount for testing'
),
SizedBox(height: 20),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
MaterialButton(
height: margin_40dp,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(margin_5dp)),
minWidth: (MediaQuery.of(context).size.width * .9) / 2,
color: Theme.of(context).primaryColor,
textColor: white,
child: new Text(save),
onPressed: () => {
setState(() {
if (_formKey.currentState.validate()) {
// amountController.text.isEmpty ? amountController.text='Value require' : amountController.text='';
//this.displayResult = _calculateTotalReturns();
}
})
},
splashColor: blueGrey,
),
MaterialButton(
height: margin_40dp,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(margin_5dp)),
minWidth: (MediaQuery.of(context).size.width * .9) / 2,
color: Theme.of(context).primaryColor,
textColor: white,
child: new Text(save_and_continue),
onPressed: () => {},
splashColor: blueGrey,
)
])
]
),
),
}
RowTextInput is a different dart file that contains this code. RowTextInput.dart
import 'package:flutter/material.dart';
import 'package:finsec/utils/hex_color.dart';
class CustomTextField extends StatelessWidget {
CustomTextField({
this.textInputType,
this.textController ,
this.errorMessage,
this.labelText,
});
TextInputType textInputType;
TextEditingController textController;
String errorMessage, labelText;
#override
Widget build(BuildContext context) {
bool isError = false;
return Container(
child: TextFormField(
keyboardType: textInputType,
style: Theme
.of(context)
.textTheme
.title,
controller: textController,
validator: (String value) {
if (value.isEmpty) {
return errorMessage;
}
},
decoration: InputDecoration(
labelStyle: TextStyle(
color: Colors.grey,
fontSize: 16.0
),
contentPadding: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 10.0), //size of textfield
errorStyle: TextStyle(
color: Colors.red,
fontSize: 15.0
),
border: OutlineInputBorder(
borderSide: BorderSide(width:5.0),
borderRadius: BorderRadius.circular(5.0)
)
)
),
);
}
}
i want to access isError and isButtonPressed variables located in main.dart from RowTextInput.dart and be able to assign values. main.dart should then be able to see those values assign in RowTextInput.dart file.
also,i want to move the MaterialButton button in its own widget file (button.dart) but then i dont know how this dart file will interact with the main.dart file when button is click or to check values of isError and IS button pressed. basically, i am breaking the form into different components (textfield and button) and store them in their own separate file. but i want all the files main.dart, rowintputtext, button.dart(new) to be able to see values of variables in main.dart and change the values. is this possible? is there an easier way?
thanks in advance
If you think about it. In Flutter the Button and RawMaterialButton are already in other files. And the manage to do exactly what you want.
You should create a File mycustomButtons.dart.
In the file you should create a class that will build your Buttons...
But it must has two parameters in it's constructor actionSave actionSaveAndContinue.
You will then create two functions in your main something like:
void _save() {
setState(() {
if (_formKey.currentState.validate()) {
// amountController.text.isEmpty ? amountController.text='Value require' : amountController.text='';
//this.displayResult = _calculateTotalReturns();
}
})
}
Then you should pass your created functions as parameters:
MyCustomButtons(actionSave: _save, actionSaveAndContinue: _saveAndContinue)
So the button will have all needed information to update your main.dart variables.
The textField is pretty much the same. But you will need pass a validation function and a TextEditingController.
You can see the font of RawnMaterialButton, TextFormField to see how they receive (and pass) data from one class to an other.
I was also looking for breaking a form into multiple classes. This is that I did :
Form
Pass the onSaved function at the form level.
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
_CustomFormField(
onSaved: (value) => _myModelForm.field1 = value),
),
_CustomFormField2(
onSaved: (value) => _myModelForm.field2 = value),
)
),
RaisedButton(
onPressed: () {
// Validate will return true if the form is valid, or false if
// the form is invalid.
if (_formKey.currentState.validate()) {
// Process data.
_formKey.currentState.save();
// Observe if your model form is updated
print(myModelForm.field1);
print(myModelForm.field2)
}
},
child: Text('Submit'),
),
],
),
);
}
_CustomFormField1
The onSaved function will be passed as argument. This class can be either in the same file than the form or in another dedicated file.
class _CustomFormField1 extends StatelessWidget {
final FormFieldSetter<String> onSaved;
//maybe other properties...
_CustomFormField1({
#required this.onSaved,
});
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 10.0),
child: TextFormField(
// You can keep your validator here
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
onSaved: onSaved,
),
);
}
}
Like onSaved, you can do the same way for focusNode, onFieldSubmitted, validator if needed in
I hope it will help you and others
There's probably a more elegant way to do it but I am currently experimenting with Singletons. See the code below:
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import 'dart:async';
class AppModel {
TextEditingController nameController;
TextEditingController surnameController;
StreamController<String> fullnameStreamController;
AppModel() {
nameController = TextEditingController();
surnameController = TextEditingController();
fullnameStreamController = StreamController.broadcast();
}
update() {
String fullname;
if (nameController.text != null && surnameController.text != null) {
fullname = nameController.text + ' ' + surnameController.text;
} else {
fullname = 'Please enter both names';
}
fullnameStreamController.add(fullname);
}
}
GetIt getIt = new GetIt();
final appModel = getIt.get<AppModel>();
void main() {
getIt.registerSingleton<AppModel>(AppModel());
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: 'Singleton Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String text;
update() {
setState(() {
});
}
#override
void initState() {
text = 'waiting for input';
appModel.fullnameStreamController.stream.listen((data) {
text = data;
update();
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Container(
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
decoration: BoxDecoration(color: Colors.amberAccent),
child: Column(
children: <Widget> [
Card(
color: Colors.white,
child: Text('Name'),
),
Card(
color: Colors.yellow,
child: NameTextField()
),
Divider(),
Card(
color: Colors.white,
child: Text('Surname'),
),
Card(
color: Colors.yellow,
child: SurnameTextField()
),
OkButton(),
Card(
color: Colors.white,
child: Text('Full name'),
),
Card(
color: Colors.orange,
child: FullnameText(text),
),
],
),
),
);
}
}
class NameTextField extends StatefulWidget {
NameTextField({Key key}) : super(key: key);
_NameTextFieldState createState() => _NameTextFieldState();
}
class _NameTextFieldState extends State<NameTextField> {
#override
Widget build(BuildContext context) {
return Container(
child: TextField(
controller: appModel.nameController,
),
);
}
}
class SurnameTextField extends StatefulWidget {
SurnameTextField({Key key}) : super(key: key);
_SurnameTextFieldState createState() => _SurnameTextFieldState();
}
class _SurnameTextFieldState extends State<SurnameTextField> {
#override
Widget build(BuildContext context) {
return Container(
child: TextField(
controller: appModel.surnameController,
),
);
}
}
class FullnameText extends StatefulWidget {
FullnameText(this.text,{Key key}) : super(key: key);
final String text;
_FullnameTextState createState() => _FullnameTextState();
}
class _FullnameTextState extends State<FullnameText> {
#override
Widget build(BuildContext context) {
return Container(
child: Text(widget.text),
);
}
}
class OkButton extends StatefulWidget {
OkButton({Key key}) : super(key: key);
_OkButtonState createState() => _OkButtonState();
}
class _OkButtonState extends State<OkButton> {
#override
Widget build(BuildContext context) {
return Container(
color: Colors.white10,
child: RaisedButton(
color: Colors.white,
child: Icon(Icons.check),
onPressed: () {appModel.update();},
),
);
}
}
Check how I use the three controllers in the update function of the AppModel class.
CustomTextFields must extends parent(widget where is form) in this case it is ThirdFragment
class CustomTextField extends ThirdFragment{
CustomTextField({
this.textInputType,
this.textController,
this.errorMessage,
this.labelText,
});