I'm trying to set an initial value for the text field. But I Can't set the initial value in text form field. I'm getting this error 'initialValue == null || controller == null': is not true .
code:
Widget buildFirstName(BuildContext context) {
valueBuilder = valueBuild();
return TextFormField(
controller: firstNameController,
initialValue: valueBuilder,
decoration: InputDecoration(
hintText: "Enter Name",
fillColor: Colors.white,
hintStyle: TextStyle(
color: Color.fromRGBO(0, 0, 0, 1.0),
fontFamily: "SFProText-Regular"),
),
validator: validatingName,
);
}
You can't use both initialValue and controller at the same time. So, it's better to use controller as you can set default text in its constructor.
Here is an example.
// Create the controller.
final controller = TextEditingController(text: "Your initial value");
Widget build(BuildContext context) {
return TextFormField(
controller: controller, // Assign it here.
// ...
);
}
To get the value entered by the user, use:
controller.text
You cannot have controller and initialValue for TextFormField at the same time which we know from #CopsOnRoad thread.
Besides of passing default text to the constructor of controller, you can modify the value of the TextFormField by assigning value to the controller text
firstNameController.text = valueBuilder;
Related
As soon as a TextField gets focused, an object which stores if it's enabled changes so that the TextField gets disabled immediately. This also happens when another TextField above gets focused.
The TextField is placed inside a StatefulWidget and a Category object contains another object called Goal which contains a bool variable if it's enabled or disabled. This variable is also used to enable or disable the TextField.
TextField(
controller: _goalAmountController,
enabled: widget.category.goal.enabled,
decoration: InputDecoration(
labelText: "Goal Amount",
border: OutlineInputBorder(),
),
onChanged: (value) {
try {
widget.category.goal.amount = double.parse(value);
} on Exception {
//TODO display error message
print("Invalid Goal-Amount");
}
},
),
There's also a switch below the TextField to enable or disable the Goal by setting it's enabled variable.
SwitchListTile(
value: widget.category.goal.enabled,
title: Text("Enable Goal"),
onChanged: (value) {
setState(
() {
widget.category.goal.enabled = value;
},
);
},
),
I found out that it seems as if the click on a TextField would replace the Goal object with a new one which has false as the default value for enabled.
Try to use FocusNodes instead :
FocusNode textNode = FocusNode();
TextField(
focusNode: textNode,
controller: _goalAmountController,
enabled: widget.category.goal.enabled,
decoration: InputDecoration(
labelText: "Goal Amount",
border: OutlineInputBorder(),
),
later when you want to disable this textField when the user interact with another widget you can call:
textNode.unfocus() ;
The full page code is very long but my DropdownButton widget code like this.
The problems are,
first: I can't update my selectedCity, it doesn't get an update. Also, the print function calls null, since my cityList data is like [new york, paris, london] etc...
second: flutter doesn't change focus from any TextField to DropdownButton fully. I mean, clicked TextField, then DropdownButton but focus reverts to that TextField after the button click. It is default action of Flutter?
List<dynamic> _cityList;
String _selectedCity;
#override
Widget build(BuildContext context) {
return DropdownButton(
value: _selectedCity,
style: TextStyle(
fontSize: 11,
color: textColor,
),
items: _cityList.map((city) {
return DropdownMenuItem<String>(
child: Padding(
padding: const EdgeInsets.only(left: 4),
child: Text(city),
),
);
}).toList(),
onChanged: (String value) {
setState(() {
_selectedCity = value;
print(_selectedCity);
});
},
isExpanded: true,
);
}
Edit: The solution of resetting FocusNode after selecting an item from DropdownMenuItem is adding this line inside of setstate like this:
this: FocusScope.of(context).requestFocus(new FocusNode());
to here: onChanged:(){setSate((){here}}
I hope it will help you. I have modified your code a little bit
List<dynamic> _cityList;
String _selectedCity;
It will show the Dropdown Button and when you click on it and select any value showing in the print
#override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return Scaffold(
body: ListView(
children: [
Column(
children: <Widget>[
DropdownButton<String>(
items: _cityList.map((dynamic value) {
return DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
onChanged: (value) {
setState(() {
_selectedCity = value;
print(_selectedCity);
});
},
),
],
),
],
),
);
}
for the focus problem you should use focusNodes one with the drop down list and another with the text field https://docs.flutter.io/flutter/widgets/FocusNode-class.html.
I am using flutter to make a simple application.
In the below code, when TextBox changed event is fired then I call the method named updateTitle().
But I have to call the same method updateTitle(), when key is up, as we use in javascript and other languages too.
TextField(
controller: titleController,
style: textStyle,
onChanged: (value) => updateTitle(),
decoration: InputDecoration(
labelText: "Title",
labelStyle: textStyle,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
)),
),
For your use case, the onChangedworks just like onkyeup would work. Everytime that the user tap a new character in the textfield, it is fired.
In order to enable/disable a button you should listen to this event, do the test to see if the field isn't empty, modify a variable that will handle the button state, and call setState().
This is just a sample code. Not tested, but should work as is.
class _SoAnswerState extends State<SoAnswer> {
bool _buttonActive = false;
#override
Widget build(BuildContext context) {
...
TextField(
controller: titleController,
style: textStyle,
onChanged: (value) => updateButtonState(value), // onChanged return the value of the field
decoration: InputDecoration(
labelText: "Title",
labelStyle: textStyle,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(5.0),
)
),
),
...
}
void updateButtonState(String text){
// if text field has a value and button is inactive
if(text != null && text.length > 0 && !_buttonActive){
setState(() {
_buttonActive = true;
}
}else if((text == null || text.length == 0) && _buttonActive){
setState(() {
_buttonActive = false;
}
}
}
Edit: add more information about the events
In JavaScript, the onkeyup event handler fires when the user releases a key that was previously pressed. When the user press and release a key inside a text field, the text field value changes. The onChanged listener in Flutter fires when the text field value changes. When working with a typing interface, where the user uses a tradicional keyboard, it is not a good idea to listen to all the changes of a text field, because the user can press and hold a key, leading the application to repeat the onchanged event too many times, once for every character repetition. That's not the case with a mobile interface, where the user (usually) can't press and hold a key.
The TextField should be changed, if the String - Variable is changed from some other method.
The text box should therefore receive an update if the user enters a new text or the associated variable has been changed from another location.
//Calling new text boxes
new eingabeTextbox(false, "Bemerkungen", "...", (String str){zahlerBemerkungen = str; print("neuer Bemerkungswert:" + str);},zahlerBemerkungen),
//paged class to avoid source code redundancy
class eingabeTextbox extends StatelessWidget {
final bool _nummerischeTastatur;
final String _ueberschrift;
final String _platzhalter;
ValueChanged<String> eingegebenerWert;
ValueChanged<String> variableUeberwachen;
eingabeTextbox(this._nummerischeTastatur, this._ueberschrift, this._platzhalter, this.eingegebenerWert, this.variableUeberwachen);
#override
Widget build (BuildContext context){
return new TextField(
keyboardType: _nummerischeTastatur == true ? TextInputType.number : TextInputType.multiline,
decoration: new InputDecoration(
labelText: _ueberschrift,
hintText: _platzhalter
),
onSubmitted: eingegebenerWert,
onChanged: variableUeberwachen
);
}
}
My approach with "ValueChanged variableUeberwachen;" does not work.
Can someone help me?
I have this code from a stateful widget which looks like
static String code = '+1';
String phone;
String finalphone = '$code' + '$phone'; =>this declaration brings an error
that 'Only static members can be accessed in initializers'
How am I supposed to bring the two variables together so that i have something that looks like +1535465345 i am collecting user information
//the widget
Widget form() {
return Form(
key: _formKey,
child: TextFormField(
decoration: InputDecoration(
contentPadding: EdgeInsets.all(0.0),
),
style: TextStyle(
letterSpacing: 2.0,
fontSize: 19.0,
fontWeight: FontWeight.bold,
color: Colors.black87),
onSaved: (value) => phone = value, //the (value) here is a
//string which is
//assigned
//to phone variable declared at the top
),
),
);
}
also making the phone variable static and printing out the concatenated string brings out +1null
Instead of having a field, you can have a getter like
String get finalphone => '$code' + '$phone';
Refer this answer
You need to specify the class to access static members
String finalphone = '${MyClass.code}$phone';
sure it will bring an error you use the phone variable before give it a value so it will fire null reference exception .
whatever here is a complete fix hope it will work :
static String code = '+1';
String phone;
String finalphone = "";
//the widget
Widget form() {
return Form(
key: _formKey,
child: TextFormField(
decoration: InputDecoration(
contentPadding: EdgeInsets.all(0.0),
),
style: TextStyle(
letterSpacing: 2.0,
fontSize: 19.0,
fontWeight: FontWeight.bold,
color: Colors.black87),
onSaved: (value) {phone = value; finalphone = '$code' + '$phone'; }
),
),
);
you may need to use setState to asign value and rebuild the view .