When using Form validator the default position of the message label is on the bottom, is there a way to put it on the top of the Text field?
You can not change position on validation label in TextFormField
But you can build your own TextFormField by using FormField widget and custumize its children to look like a normal TextFormField this is a working example made with FormField
FormField(
// initialValue: 0,
autovalidate: true,
validator: normalValidator,
builder: (state) {
state.validate();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
state.errorText!=null? Text(state.errorText, style: TextStyle(color: Colors.red, fontSize: 12),):Container(),
DropdownButton(
isExpanded: true,
value: state.value,
items: _choices,
onChanged: (v) {
state.didChange(v);
setState((){});
}),
],
);
}),
You can now customize it to sweet your needs. Find more about FormField here on official doc
Related
I am trying to modify a TextField inside an ExpansionTile title and when I modify the text I want to update data in my database firestore, this part works fine. The problem is when I write something in my TextField I can only write one letter and then I have to select the TextField again.Initial text field value
Second text field value
In the second picture after writing the number 2 in test the 'blue mark' exits the TextField and if I want to write in the TextField again I have to select the text field again.
This is the TextField code inside the expansion tile, all this code is inside a stream where each list tile is an entry from the database:
return SizedBox(
width: double.infinity,
child: SingleChildScrollView(
child: Column(
children: [
Column(
children: [
ListView.builder(
physics: const ClampingScrollPhysics(),
shrinkWrap: true,
itemCount: widget.shoppingListsCart.length,
itemBuilder: (BuildContext context, int index) {
String shoppingCartListName =
widget.shoppingListsCart.elementAt(index).name;
final shoppingListId =
widget.shoppingListsCart.elementAt(index).shoppingListId;
TextEditingController _textEditingControllerShoppingListName = TextEditingController();
_textEditingControllerShoppingListName.text = shoppingCartListName;
_textEditingControllerShoppingListName.addListener(() {
widget.firebaseCloudStorage.updateShoppingListName(
widget.shoppingCartListId, shoppingListId, _textEditingControllerShoppingListName.text);
});
return Column(
children: [
ExpansionTile(
backgroundColor: Colors.indigo,
title: SizedBox(
child: Row(
children: [
SizedBox(
width: 220,
child: TextField(
decoration: const InputDecoration(
border: InputBorder.none,
counterText: '',
),
controller: _textEditingControllerShoppingListName,
maxLength: 35,),
), ),
Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
IconButton(onPressed: (){
}, icon:Icon(Icons.edit,)),
IconButton(onPressed: () {}, icon: Icon(Icons.delete)),
],
),
]),
),
children: [
ProductsInShoppingListView(
shoppingListName: shoppingCartListName,
shoppingCartId: widget.shoppingCartListId,
shoppingListId: shoppingListId,
firebaseCloudStorage: widget.firebaseCloudStorage,
),
]),
],
);
},
),
Column(
children: [
ProductsInCartView(
shoppingCartId: state.shoppingCartId),
],
),
],
),],
),
),
);
I tried using a Future in the text field and changing from a stateless widget to a stateful widget, the error is something like this TextField accepts only one letter and loses focus after each letter but since I am using flutter that solution didn't work for me. I don't know what is the error because the console doesn't say anything. Please help, thank you.
did you try it? It's TextFormField. Here I fixed the value 1, we can make it a dynamic value. But I hope this will be helpful to think about next.
TextFormField(
onChanged: (value) {
if (value.length == 1) {
FocusScope.of(context).nextFocus(); //whatever you want to do
}
},
inputFormatters: [
LengthLimitingTextInputFormatter(1)
],
),
A TextFormField has a native error animation if a validation occurs. The labelText turns red and slightly wiggles from left to right. Furthermore, a red validation text slides down underneath the text area.
But Checkbox validation in flutter is unfortunately not natively supported.
I would like the same kind of animation that Vuetify supports: https://vuetifyjs.com/en/components/forms/#misc (click on the validate button, and notice how the Checkbox behaves) which is similar to how flutter does it.
So is it possible to extract/copy these error animations/transitions from the flutter framework and use them on a Checkbox/Text (or other places for that matter)?
This is my wrapped checkbox that shows an error text underneath the checkbox if it does not validate (the value is false):
class MyCheckbox extends FormField<bool> {
MyCheckbox({required String title, required FormFieldSetter<bool> onSaved, FormFieldValidator<bool>? validator, bool initialValue = false})
: super(
onSaved: onSaved,
validator: validator,
initialValue: initialValue,
builder: (FormFieldState<bool> state) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Builder(
builder: (BuildContext context) => CheckboxListTile(
contentPadding: EdgeInsets.only(left: 0),
activeColor: Color(0xff00aeef),
side: BorderSide(color: state.hasError ? Theme.of(context).errorColor : Theme.of(context).primaryColor),
title: Text(title, style: TextStyle(color: state.hasError ? Theme.of(context).errorColor : Theme.of(context).primaryColor)),
value: state.value,
onChanged: state.didChange,
controlAffinity: ListTileControlAffinity.leading,
),
),
if (state.hasError)
Builder(
builder: (BuildContext context) => Padding(
padding: const EdgeInsets.only(left: 10),
child: Text(
state.errorText!,
style: TextStyle(color: Theme.of(context).errorColor),
),
),
)
],
);
},
);
}
I find myself working with TextFormField hand in hand with DropdownButton. There is a strange process going on inside the view. I put the steps below:
To the TexFormField, I'm assigning an initial value: controller: _nameController..text = datumAdministrative.name.
I enter a new value to the TextFormField.
When the DropdownButton is deployed, the keyboard is closed the whole Widget is redrawn, which causes the TextFormField to recover its initial value and does not keep the new value entered.
Is there any way to avoid, that the TextFormField returns to its initial value when selecting DropdownButton? I would appreciate if you could help me with a post or feedback.
Code Scaffold:
return Scaffold(
resizeToAvoidBottomPadding: false,
resizeToAvoidBottomInset: true,
appBar: AppBar(
backgroundColor: ColorsTheme.primary,
leading: GestureDetector(
onTap: () {
Navigator.pushReplacementNamed(context, 'administrativeListData');
},
child: Container(
padding: EdgeInsets.all(16),
child: FaIcon(FontAwesomeIcons.arrowLeft)),
),
centerTitle: true,
title: Text(datumAdministrative.name +
' ' +
datumAdministrative.lastNameFather),
automaticallyImplyLeading: false),
body: Stack(
children: <Widget>[
ImageBackground(),
_sizeBoxHeight(),
Container(
child: Form(
key: formValidator.formKey,
child: ListView(
children: <Widget>[
_containerImageUser(context, datumAdministrative),
_sizeBoxHeight(),
CustomCardExpansionTile(
title: Constants.administrativeData,
icon: FontAwesomeIcons.addressBook,
widget: Container(
padding: EdgeInsets.all(15),
child: responsiveDataAdministrative(context)),
),
CustomCardExpansionTile(
title: Constants.addressInformationAdministrative,
icon: FontAwesomeIcons.houseUser,
widget: Container(
padding: EdgeInsets.all(15),
child: responsiveAddressInformationAdministrative(
context))),
CustomCardExpansionTile(
title: Constants.userDataSystem,
icon: FontAwesomeIcons.idCard,
widget: Container(
padding: EdgeInsets.all(15),
child: responsiveInformationSystemAdministrative(
context))),
],
),
),
),
],
),
);
Code TextFormField:
TextFormField(
controller: _nameController..text = datumAdministrative.name,
keyboardType: TextInputType.text,
textInputAction: null,
textCapitalization: TextCapitalization.sentences,
onChanged: (value) => formValidator.name = value,
validator: (value) {
if (formValidator.fieldValidText(value)) {
return null;
} else {
return Constants.nameAdministrativeMessage;
}
});
I see that you set the value for the text property of TextEditingController inside the build method. So, it will be invoked whenever the widget rebuilds, causing the value for the field back to the initial one.
The docs actually tells about it:
text property
Setting this will notify all the listeners of this
TextEditingController that they need to update (it calls
notifyListeners). For this reason, this value should only be set
between frames, e.g. in response to user actions, not during the
build, layout, or paint phases.
To fix it, you should remove the cascade notation here:
controller: _nameController..text = datumAdministrative.name,
Do it inside initState() instead:
#override
void initState() {
_nameController.text = datumAdministrative.name;
}
I'm trying to show element as soon as my form becomes valid. According to flutter docs I need to use _formKey.currentState.validate() but in the docs it is used on button click, while I'm trying to use it to show/hide element.
Working code (as used in flutter tutorial)
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
autovalidate: true,
validator: validateName,
),
RaisedButton(
onPressed: () => _formKey.currentState.validate()
? print('valid')
: print('not valid'))
My code with (INVALID MEMER OF NULL: 'validate) error
return Form(
key: _formKey,
child: Column(
children: [
TextFormField(
autovalidate: true,
validator: validateName,
),
_formKey.currentState.validate()
? Container(child: Text('valid'))
: Container(child: Text('not valid'))
The best answer for you will be to use TextFormField onChanged, which is of type ValueChanged, which keeps track of the changes you make in your TextFormField
Advantage
You will be able to keep a track of the text changes, and show/hide content based upon that
Disadvantage
Each TextField should be maintaining the bool for the different TextField to keep a track of the items
It is like a workaround, so can use in this way. I am using a single TextFormField to show how it works, you can then work on ther TextFormField and get it up and running.
FINAL SOLUTION
bool isValid = false;
final TextEditingController _controller = new TextEditingController();
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextFormField(
decoration: InputDecoration(hintText: 'Enter your data'),
controller: _controller,
onChanged: (String val){
setState((){
if(val.length >= 4) isValid = true;
else isValid = false;
});
}
),
SizedBox(height: 20.0),
isValid ? Text('Valid String', textAlign: TextAlign.center) : Text('Name must be more than 3 character', textAlign: TextAlign.center)
]
)
SOLUTION: For various, you must check whether all the different bools are true or not, based upon that, you can show/hide the data.
RESULT
Let me know if is of any use to you :)
Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text("Postal Code"),
TextField(
controller: controllerPostalCode,
),
// if controllerPostalCode not null
Container(
child: FutureBuilder<AddressCtrl>( //Future Builder that hold data on State and Country
future: getDataCtrl(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.result == null) {
return Container();
} else {
return Container(
child: Column(
children: <Widget>[
Text("State"),
TextField(
decoration: InputDecoration(
hintText: snapshot.data.result[index].State // value will be display after user input Postal Code text field
),
),
Text("Country"),
TextField(
decoration: InputDecoration(
hintText: snapshot.data.result[index].Country // value will be display after user input Postal Code text field
),
)
],
),
);
}
}
})),
],
),
),
I want to automatically input values to two text field (in this case: State and Country) based on value of user input on Postal Code text field without having to click on any button. I found many question regarding this issue but I couldn't find in Dart/Flutter.
Additional notes: The value of State and Country are from REST API.
use in text
var textController = new TextEditingController();
I think you can use onTextChanged method in postal code and setState to change the variable that holding the text from postal code text field. Then use it (the variable) where you want.
And this doc will help you more and more.
Hope I could help you.