Flutter Form Builder loses initialValue when no input exists for field - flutter

When using FormBuilder initialValue, it seems the values are not saved when they are not part of an input. Here is an example code snipped
FormBuilder(
initialValue: {
"id": "MyId",
"name": "Name",
},
key: _formKey,
child: Column(
children: [
FormBuilderTextField(
name: "name",
),
TextButton(
onPressed: () {
_formKey.currentState?.save();
if (_formKey.currentState?.validate() == true) {
print(_formKey.currentState!.value);
}
},
child: Text(
"Save",
),
)
],
),
)
When pressing save and inspecting the values of the form state it has only name but is missing the id attribute.
Is this intended behavior and if so, is it possible to make it keep the id field?

Related

Keyboard closes directly after opening in an extended FormField

When building a custom form field by extending FormField (with a TextFormField centered within two IconButtons), I encounter unexpected issues with the keyboard.
After a state change due to a button press, the TextFormField is only updated when it has been provided with a key during construction (e.g. UniqueKey()). However, when using keys in this way, the keyboard directly closes after opening. The keyboard only works properly when no key is provided to TextFormField. When the key from the FormField baseclass constructor is provided, the keyboard also doesn't work and TextFormField is not updated when an IconButton is pressed.
When using the iOS simulator, no error is received when the keyboard closes directly after opening. When using a physical device, I get the following error:
Successfully load keyboard extensions
[lifecycle] [u 4EF1D37A-3BC9-4488-BC5A-A32FFFD4094F:m (null)] [com.google.keyboard.KeyboardExtension(2.3.19)] RB query for the extension process state failed with error: Error Domain=RBSServiceErrorDomain Code=1 "Client not entitled" UserInfo={RBSEntitlement=com.apple.runningboard.process-state, NSLocalizedFailureReason=Client not entitled, RBSPermanent=false}
The problem occurs at various versions of flutter, among which is version 3.7.0-1.3.pre.
Is this a bug or should the keys be used in another way?
Code that illustrates the problem
class CustomNumberFormField extends FormField<double> {
final int scale;
final TextStyle? textStyle;
CustomNumberFormField({
required FormFieldSetter<double> onSaved,
this.scale = 0,
this.textStyle,
super.validator,
super.key,
super.initialValue,
}) : super(
onSaved: onSaved,
builder: (FormFieldState<double> state) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IconButton(
icon: const Icon(Icons.remove),
onPressed: () {
state.didChange((state.value != null)
? state.value! - 1
: initialValue);
},
),
SizedBox(
width: 100,
child: TextFormField(
///////////////////////////
// Problem occurs here:
key: UniqueKey(), // key: key,
// Keyboard cannot be used when the above keys are used (i.e. UniqueKey() or from baseclass).
// However, state changes due to pressing IconButton do not update text value without using UniqueKey().
// Using the baseclass key also results in closing the keyboard and IconButtons do not update TextFormField
initialValue: NumberFormat("#.#").format(state.value),
keyboardType: TextInputType.numberWithOptions(
decimal: (scale > 0)),
textAlign: TextAlign.center,
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(RegExp(
scale > 0 ? r'[0-9]+[,.]{0,1}[0-9]*' : r'[0-9]')),
TextInputFormatter.withFunction(
(oldValue, newValue) => newValue.copyWith(
text: newValue.text.replaceAll('.', ','),
),
),
],
style: textStyle,
autovalidateMode: AutovalidateMode.onUserInteraction,
onSaved: (value) {
if (value != null && value != "") {
NumberFormat().parse(value).toDouble();
}
},
),
),
IconButton(
icon: const Icon(Icons.add),
onPressed: () {
state.didChange((state.value != null)
? state.value! + 1
: initialValue);
},
),
],
),
state.hasError
? Text(
state.errorText ?? "",
style: const TextStyle(color: Colors.red),
)
: Container()
],
);
},
);
}

How to get multiple values from DropdownButtonFormField in flutter?

selecting one item from dropdown menu, i want to show its multiple values inside textfields in flutter. For example, if I select school it will show its name, location, contact no. so i need to collect multiple values from that item. how can i have multiple values from dropDownMenuItem to show multiple values?
for example School list item is given below:
"SchoolList": [
{
"name": "school1",
"location": "location1",
"contact_no": "address1"
},
{
"name": "school2",
"location": "location2",
"contact_no": "address2"
},
{
"name": "school3",
"location": "location3",
"contact_no": "address3"
},
],
at first we need to pass Item type as parameter of DropdownButtonFormField. Items will me that type of list and it will return dropDownMenuItem of that type. Then we will assign values from items inside onChanged section.
DropdownButtonHideUnderline(
child: DropdownButtonFormField<
SchoolList>(
validator: (value) => value == null
? 'field required'
: null,
value: selectedItem,
icon: const Icon(
Icons.arrow_drop_down,
color: Colors.grey,
),
iconSize: 24,
elevation: 16,
hint: Text(
'Select',
),
onChanged:
(SchoolList?
schoolList) {
setState(() {
selectedSchoolName =
schoolList!
.name;
selectedSchoolLocation =
schoolList!
.location;
selectedSchoolContactNo
=
schoolList!
.contact_no;
});
},
//
items: =
SchoolList
?.map((item) {
return DropdownMenuItem<
SchoolList>(
value: item,
child:
Text(item.name)),
);
}).toList(),
),
),

Can I get multiple return from dropdownbutton?

I tried to make json to dropdownbutton today.
But I want to get 2 values(ID and Name both) from it.
this is my json
[{"StudentID":"3","StudentName":"Amy"},{"StudentID":"4","StudentName":"Derek"}]
and this is my code of dropdown button.
Row(
children: <Widget>[Container(
padding: EdgeInsets.only(left:5),
child: new DropdownButton(
value: _StudentSelection,
items: StudentData.map((product) {
return new DropdownMenuItem(
value: product["StudentID"].toString(),
child: new Text(product["StudentName"]!)
)
}).toList(),
onChanged: (String? newValue) {
setState(() {
_StudentSelection = newValue!;
});
},
hint: Text('StudentID'),
)
),
],
),
in this case variety _StudentSelection is already initialized by Amy and StudentData is result of decoding json.
Thank you for seeing this question :)
Make your _StudentSelection variable's type the same type as your product variable and then use product as a value:, not just the ID.
Row(
children: <Widget>[Container(
padding: EdgeInsets.only(left:5),
child: new DropdownButton(
value: _StudentSelection, // change this variables type to the type of your product variable
items: StudentData.map((product) {
return new DropdownMenuItem(
value: product, // use the whole product as value
child: new Text(product["StudentName"]!)
)
}).toList(),
onChanged: (TYPE_OF_PRODUCT_HERE? newValue) {
setState(() {
_StudentSelection = newValue!;
});
},
hint: Text('StudentID'),
)
),
],
),

Retrieve the value of a Slider and send it to MySQL

I'm working on a online survey app in flutter and the API in PHP with MySQL for the database.
I'm using TextFormField for the Name field and wanted to use Slider for Age field.
I can retrieve the value from TextFormField using onSaved: (e) => name = e,, But I don't know how to retrieve the value of the Slider.
I tried to change the value to string using age.toString() but It says:
The argument type 'String' can't be assigned to the parameter type.
Here is my Form() code:
Form(
key: _key,
child: ListView(
children: [
TextFormField(
onSaved: (e) => name = e,
decoration: InputDecoration(labelText: "Name"),
),
Slider(
min: 10,
max: 100,
value: age,
onChanged: (value) {
setState(() {
age = value;
});
},
label: "$age",
),
MaterialButton(
onPressed: () {
check();
},
child: Text("submit"),
)
]
)
),

creating textbox from list in flutter

I have List like this (It keeps changing because this is the response of API,
tableValue=[
{
"id": "RegNo",
"displayName": "Enter Register No",
"type": "string",
"value": "1XYZ19AA"
},
{
"id": "name",
"displayName": "Enter Name",
"type": "string",
"value": "KARAN"
},
{
"id": "sub",
"displayName": "choose subjects",
"type": "list",
"value": ["JAVA"],
"data": [
{"id": "1", "dispId": "JAVA"},
{"id": "2", "dispId": "Python"},
{"id": "3", "dispId": "Dart"}
]
}
];
What I want to display is like below,
Based on the List, I want to display all its data,
i.e
Enter Register No --Text_Box here--
Enter Name --Text_Box here--
(How many entries have string type I want to display a text box with its display name and a value defined in the List for that map should be displayed example 1XYZ19AA on the textbox),
If there are n entries with the type string n text box with the display name should be displayed, and I want to have the control over the data entered.
If there are 3 text boxes in the list if the user enters all or only 1 I should be able to access that uniquely.
Question
Can you suggest any way of displaying if its a type list, because elements in a list should have a multi-select option?
Thank you
ListView.builder(
itemCount: tableValue.length,
itemBuilder:(context, index){
return Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height/10,
child: Row(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width/2,
height: MediaQuery.of(context).size.height/10,
alignment: AlignmentDirectional.centerStart,
child:Text(tableValue[index]['displayName'])
),
Container(
width: MediaQuery.of(context).size.width/2,
height: MediaQuery.of(context).size.height/10,
alignment: AlignmentDirectional.centerStart,
child: TextField(
decoration: InputDecoration.collapsed(
hintText: "blah"
)
)
)
],
)
);
}
)
Here is an example where you can show the data from the table and also you can see how to access the selected values of the TextFields and Checkboxs
Note that you may need to change the type of tableValue like this:
List<Map<String, dynamic>> tableValue = [...]
Map<String, TextEditingController> controllers = {};
Set<String> checks = {};
This would be the body of your screen
ListView(
children: <Widget>[
Column(
children: tableValue
.where((entry) => entry["type"] == "string")
.map((entry) => Row(
children: <Widget>[
Text(entry["displayName"]),
Flexible(
child: TextField(
controller: getController(entry["id"]),
),
)
],
)).toList(),
),
Column(
children: tableValue
.firstWhere(
(entry) => entry["type"] == "list")["data"]
.map<Widget>(
(data) => CheckboxListTile(
title: Text(data["dispId"]),
value: checks.contains(data["id"]),
onChanged: (checked) {
setState(() {
checked ? checks.add(data["id"]) : checks.remove(data["id"]);
});
},
),
).toList(),
),
Text("Texts: ${controllers.values.map((controller) => controller.text)}"),
Text("Checks: ${checks.map((check) => check)}"),
],
)
And this is how you could handle the TextField controllers
TextEditingController getController(String id) {
controllers.putIfAbsent(id, () => TextEditingController());
return controllers[id];
}