why does Flutter form reset all fields when I click submit? - forms

I have a FORM withe 32 TEXTFORMFIELDS and abutton to validate and navigate to output screen.
TextButton(
onPressed: () {
_formKey.currentState.save(); // I added this line which does nothing
if (_formKey.currentState.validate()) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return OutputScreen();
},
),
);
} else {
_showAlert(context); // third partypackage alert function
}
},
child: Text(
'Calculate',
),
),
My problem is that if the user clicked submit, sometimes it resets all fields whether the validation was true or false;
Here is a thing I found after a lot of testing, when the user inputs a text field, the input keyboard has a "DONE" key, which the user can use to end editing. Now if the user didn't use it and jus tapped on the next field for input and continues to click the subit button I created, it resets all form.
Any ideas?
or is there a way to force user to click 'DONE' on the keyboard once finished input.
Thanks in advance.
///////////////////////////////////////////////////
EDIT: Full code sample
///////////////////////////////////////////////////
class CementInputPage extends StatefulWidget {
#override
_CementInputPageState createState() => _CementInputPageState();
}
class _CementInputPageState extends State<CementInputPage> {
static const double sizedBoxHeight = 8;
final _formKeyCement = GlobalKey<FormState>();
CementData cementData = new CementData();
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFFDDDDDD),
appBar: AppBar(
title: Text("Cement Input Data"),
),
body: SafeArea(
child: Form(
key: _formKeyCement,
child: ListView(
children: [
// Header data
WhiteBoxContainer( //container I created in another file
boxTitle: 'Header',
childWidget: Column(
children: [
//TODO: Validate date format
myStringTextInputRow('Date'),
SizedBox(height: sizedBoxHeight),
myStringTextInputRow('Operator Company'),
SizedBox(height: sizedBoxHeight),
myStringTextInputRow('Cement Contractor'),
SizedBox(height: sizedBoxHeight),
myStringTextInputRow('Well Name'),
SizedBox(height: sizedBoxHeight),
myStringTextInputRow('Field Name'),
SizedBox(height: sizedBoxHeight),
myStringTextInputRow('Rig'),
SizedBox(height: sizedBoxHeight),
myStringTextInputRow('Rig Supervisor'),
SizedBox(height: sizedBoxHeight),
myStringTextInputRow('Cement Supervisor'),
SizedBox(height: sizedBoxHeight),
],
),
),
//
//Well data
WhiteBoxContainer(
boxTitle: 'Well Data',
childWidget: Column(
children: [
Row(
children: [
Expanded(
child: TextFormField(
keyboardType:
TextInputType.numberWithOptions(decimal: true),
autovalidateMode:
AutovalidateMode.onUserInteraction,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: "Section Depth (ft)",
),
validator: (value) {
return sectionTDValidator(value);
},
),
),
checkInputStatus(InputValidationStatus.notValid),
],
),
SizedBox(height: sizedBoxHeight),
Row(
children: [
Expanded(
child: TextFormField(
keyboardType:
TextInputType.numberWithOptions(decimal: true),
autovalidateMode:
AutovalidateMode.onUserInteraction,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: "Casing length (ft)",
),
validator: (value) {
return casingLengthValidator(value);
},
),
),
checkInputStatus(InputValidationStatus.notValid),
],
),
Container(
child: TextButton(
onPressed: () {
_formKeyCement.currentState.save(); // line I added which did nothing
if (_formKeyCement.currentState.validate()) {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return CementOutputScreen();
},
),
);
} else {
//I want to show an alert dialog
child: Text(
'Calculate',
),
),
),
],
),
),
),
);
}
String sectionTDValidator(String value) {
if (value.isNotEmpty) {
cementData.sectionTD = double.parse(value);
if (cementData.sectionTD < kMinWellDepth) {
return 'Section Depth is too short!';
} else if (cementData.sectionTD > kMaxWellDepth) {
return 'Section depth is too long!';
} else if (cementData.casingLength != null &&
cementData.casingLength > cementData.sectionTD) {
return 'Section depth is shorter than casing length!';
}
} else {
cementData.sectionTD = null;
}
return null;
}
String casingLengthValidator(String value) {
if (value.isNotEmpty) {
cementData.casingLength = double.parse(value);
if (cementData.casingLength < kMinWellDepth) {
return 'Casing Length is too short!';
} else if (cementData.casingLength > kMaxWellDepth) {
return 'Casing Length is too long!';
} else if (cementData.sectionTD != null &&
cementData.casingLength > cementData.sectionTD) {
return 'Casing Length is longer than section depth!';
} else if (cementData.leadLength != null) {
if (cementData.leadLength > cementData.casingLength) {
return 'Casing length is shorter than lead length!';
} else if (cementData.tailLength != null) {
// check tail length
if (cementData.tailLength > cementData.casingLength) {
return 'Casing length is shorter than lead length!';
} else if ((cementData.leadLength + cementData.tailLength) >
cementData.casingLength) {
return 'Casing length is shorter than total cement length!';
}
}
} else if (cementData.shoeTrackLength != null &&
cementData.shoeTrackLength >= cementData.casingLength) {
return 'Shoe track length is >= casing length!';
}
} else {
cementData.casingLength = null;
}
return null;
}
String shoeTrackLengthValidator(String value) {
if (value.isNotEmpty) {
cementData.shoeTrackLength = double.parse(value);
if (cementData.casingLength != null &&
cementData.shoeTrackLength >= cementData.casingLength) {
return 'Shoe track length is >= casing length!';
}
} else {
cementData.shoeTrackLength = null;
}
return null;
}
String stickUpLengthValidator(String value) {
if (value.isNotEmpty) {
cementData.stickUpLength = double.parse(value);
if (cementData.stickUpLength > kMaxStickUpLength) {
return 'Stick up length is too long!';
}
} else {
cementData.stickUpLength = null;
}
return null;
}
}
Row myStringTextInputRow(String labelText) {
return Row(
children: [
Expanded(
child: TextFormField(
keyboardType: TextInputType.name,
maxLines: 2,
minLines: 1,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: labelText,
),
),
),
checkInputStatus(InputValidationStatus.notCritical),
],
);
}
Container checkInputStatus(InputValidationStatus inputStatus) {
if (inputStatus == InputValidationStatus.notValid) {
return Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(left: 3),
child: Icon(
Icons.clear,
color: Colors.red[900],
size: 18.0,
semanticLabel: 'Feedback icon',
),
);
} else if (inputStatus == InputValidationStatus.valid) {
return Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(left: 3),
child: Icon(
Icons.done,
color: Colors.green[900],
size: 18.0,
semanticLabel: 'Feedback icon',
),
);
} else {
return Container(
alignment: Alignment.centerLeft,
padding: EdgeInsets.only(left: 3),
child: Icon(
Icons.flaky,
color: Colors.orange[700],
size: 18.0,
semanticLabel: 'Feedback icon',
),
);
}
;
}

Try adding TextEditingController to yours TextFormFields and removing the autovalidateMode.

This might be because you are using ListView to render your children. ListView only renders the visible children (has recycling nature). Instead, use Column with SingleChildScrollView.
SingleChildScrollView(child:Column(children:yourFormChildren));
Also check: flutter form data disappears when I scroll

Related

how to disable submit button until fields are not filled up properly in flutter

Creating a demo for setting submit button disabled until all are required TextField is not empty...
username and password TextField are empty.. then submit button should be disabled...
I have done with my basic way, but looking for advanced code so that it can be not repeated typing like I have more text fields
here is my basic code...
class _Stack4State extends State<Stack4> {
TextEditingController txtusername = TextEditingController();
TextEditingController txtpassword = TextEditingController();
bool isenable = false;
void checkfieldvalue(String username, String password) {
if (username.length > 3 && password.length > 6) {
setState(() {
isenable = true;
});
} else {
setState(() {
isenable = false;
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.grey[300],
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
const SizedBox(
height: 20,
),
TextField(
controller: txtusername,
onChanged: (value) {
checkfieldvalue(txtusername.text, txtpassword.text);
},
),
SizedBox(
height: 20,
),
TextField(
controller: txtpassword,
onChanged: (value) {
checkfieldvalue(txtusername.text, txtpassword.text);
}),
const SizedBox(
height: 20,
),
ElevatedButton(
child: isenable ? Text('Register') : Text('Fill Data First'),
onPressed: () {
if (isenable == true) {
//code for submit
}
},
),
]),
),
),
);
}
}
First define this variable:
final _formKey = GlobalKey<FormState>();
then use Form widget inside your widget tree like this:
SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Form(
key: _formKey,
child: Column(
children: [
const SizedBox(
height: 20,
),
TextField(
controller: txtusername,
onChanged: (value) {
checkfieldvalue(
txtusername.text, txtpassword.text);
},
validator: (value) {
if (value == null || value.isEmpty) {
return 'username is empty';
}else if (value.characters.length < 4){
return 'username is in wrong format';
}
return null;
},
),
SizedBox(
height: 20,
),
TextField(
controller: txtpassword,
onChanged: (value) {
checkfieldvalue(
txtusername.text, txtpassword.text);
},
validator: (value) {
if (value == null || value.isEmpty) {
return 'password is empty';
}else if (value.characters.length < 4){
return 'password is in wrong format';
}
return null;
},
),
const SizedBox(
height: 20,
),
],
)),
ElevatedButton(
child:
Text('Register'),
onPressed: _formKey.currentState != null &&
_formKey.currentState.validate()
? () {}
: null,
),
]),
),
),
and use its key to handle validation state. You can set your checkfieldvalue in validator.
You can addListener
#override
void initState() {
super.initState();
txtusername.addListener(() {
checkfieldvalue(txtusername.text, txtpassword.text);
setState(() {});
});
txtpassword.addListener(() {
checkfieldvalue(txtusername.text, txtpassword.text);
setState(() {});
});
}
And button
ElevatedButton(
child: isenable ? Text('Register') : Text('Fill Data First'),
onPressed: isenable
? () {
if (isenable == true) {
//code for submit
}
}
: null,
),

Keyboard trigger the api call while closing and opening in flutter?

Keyboard triggers the api calling while closing and opening
I have search bar I didn't pass anything inside the search bar but when I click the search bar The api call will run.
I don't know why that thing was happen I tried several ways but It won't work
Even Inside the keyboard I choose the one hand keyboard that time also api will run
Also tried the Focusnode also.
class PopupNaviagator extends StatefulWidget {
var body;
String leadsName = "";
Map<String, dynamic> listValues;
PopupNaviagator(this.listValues);
var data;
String pageData = "";
double totalPageCount = 0;
int pageIncrementer = 1;
#override
_PopupNavigatorState createState() => _PopupNavigatorState();
}
class _PopupNavigatorState extends State<PopupNaviagator> {
Utils util = new Utils();
bool isSearching = false;
#override
void initState() {
super.initState();
}
String searchingText = "";
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
titleSpacing: 0,
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: util.getColors(1001),
stops: [0.1, 5.0],
),
),
),
title: !isSearching
? Text("Select Search Type")
: TextField(
autofocus: true,
autocorrect: true,
onChanged: (value) {
searchingText = value;
},
cursorColor: Colors.white,
onSubmitted: (value) {
searchingText = value;
campaignAPI(
widget.listValues["colname"].toString(),
widget.pageIncrementer.toString(),
searchingText, // search key
1, // flag
);
},
style: TextStyle(color: Colors.white),
decoration: InputDecoration(
icon: Icon(Icons.search),
hintText: "Search ",
hintStyle: TextStyle(color: Colors.white)),
),
actions: <Widget>[
isSearching
? IconButton(
icon: Icon(Icons.cancel),
onPressed: () {
setState(() {
searchingText = "";
this.isSearching = false;
campaignAPI(
widget.listValues["colname"].toString(),
widget.pageIncrementer.toString(),
searchingText, // search key
1, // flag
);
/* filteredCountries = countries;*/
});
},
)
: IconButton(
icon: Icon(Icons.search),
onPressed: () {
setState(() {
this.isSearching = true;
});
},
)
],
),
body: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(Radius.circular(5))),
child: Scaffold(
body: FutureBuilder(
future: campaignAPI(widget.listValues["colname"].toString(), "1",
searchingText, 0),
builder: (context, snapshot) {
if (snapshot.hasData) {
var body;
if (widget.data == null) {
body = snapshot.data;
} else {
body = widget.data;
}
final records = body["list_records"];
widget.pageData = body["PageValues"];
widget.totalPageCount =
(body["TotalRecordCount"] / 5).toDouble();
return Scaffold(
body: Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
if (records.length != 0) ...[
Expanded(
child: ListView.builder(
padding: EdgeInsets.only(
top: 0,
bottom: 0,
),
physics: ClampingScrollPhysics(),
shrinkWrap: true,
itemCount: records.length,
itemBuilder: (context, index) {
Map<String, dynamic> pickerValues =
records[index];
String titleName =
pickerValues["viewcol_value"]
.toString();
return Container(
margin: const EdgeInsets.all(5.00),
decoration: new BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.grey, width: 1.0),
borderRadius: new BorderRadius.all(
Radius.circular(3.0)),
),
child: FlatButton(
padding: EdgeInsets.all(8.0),
onPressed: () {
setState(() {
List<String> strArr = [
titleName,
pickerValues["rec_id"].toString(),
widget.listValues["colname"]
];
Navigator.pop(context, strArr);
});
},
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(titleName.toString()),
Icon(
Icons.check_circle_outlined,
color: Colors.grey,
),
]),
),
);
}),
),
] else ...[
Container(
height: MediaQuery.of(context).size.height / 1.4,
child: Center(
child: Container(
padding: EdgeInsets.all(65),
child: Text(
"No Record Found",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 20,
color: Colors.black),
),
decoration: BoxDecoration(
border: Border.all(
color: Colors.grey,
width: 2,
),
)),
),
),
],
if (records.length != 0) ...[
Container(
child: Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: () {
if (widget.pageIncrementer > 1) {
widget.pageIncrementer--;
campaignAPI(
widget.listValues["colname"]
.toString(),
widget.pageIncrementer.toString(),
searchingText, // search key
1, // flag
);
setState(() {});
} else {
util.showToast("No records to show");
}
},
child: Icon(Icons.arrow_left_rounded,
size: 50, color: Colors.white),
),
Text(
widget.pageData,
style: TextStyle(
fontSize: 15,
color: Colors.white,
fontWeight: FontWeight.bold),
),
InkWell(
onTap: () {
if (widget.totalPageCount > 1 &&
widget.totalPageCount >=
widget.pageIncrementer) {
widget.pageIncrementer++;
campaignAPI(
widget.listValues["colname"]
.toString(),
widget.pageIncrementer.toString(),
searchingText, // search key
1, // flag
);
} else {
util.showToast("No reocrds to show");
}
},
child: Icon(Icons.arrow_right_rounded,
size: 50, color: Colors.white),
),
],
),
decoration: BoxDecoration(
gradient: LinearGradient(
colors: util.getColors(1001),
stops: [0.1, 5.0],
),
),
)
]
],
),
),
);
} else if (snapshot.hasError) {
return Text('${snapshot.error.toString()}');
}
return Center(
child: CircularProgressIndicator(),
);
},
),
),
));
}
campaignAPI(
String field_col, String page_no, String searchValue, int flag) async {
Utils util = new Utils();
SharedPreferences prefs = await SharedPreferences.getInstance();
final accessKey = prefs.getString('access_key');
final companyName = prefs.getString('company_name');
Object requestParam = {
"companyname": companyName,
"access_key": accessKey.toString(),
"field_col": field_col,
"page_no": page_no,
"searchValue": searchValue,
};
print(requestParam.toString());
APIS apis = new APIS();
Uri url = Uri.parse(apis.searchquickcreate);
util.prints(url);
util.prints(requestParam);
final response = await http.post(url, body: requestParam);
if (response.statusCode == 200) {
final body = json.decode(response.body);
print(body);
String status = body["status"];
if (status != "failed") {
if (flag == 1) {
setState(() {
widget.data = body;
});
}
return body;
} else {
util.logOut(context);
return body;
}
} else {
Navigator.pop(context);
util.showToast("Server Error !");
throw Exception("Server Error !");
}
}
}

How set form validation in widget flutter

I'm working on flutter project .I have a revision form validator that is not working as expected. When I leave the TextFormField empty the validator doesn't show me anything. I want to stay on the revision form until I enter the values.
thanks in advance
my code :
class Revision extends StatefulWidget {
}
class _RevisionState extends State<Revision> with TickerProviderStateMixin {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
RevisionApi revisionApi = RevisionApi();
TextEditingController _Kilometrage_revisionController =
TextEditingController();
_showAddDialog() async {
await showDialog(
context: context,
builder: (context) => AlertDialog(
backgroundColor: Colors.white,
title: Text("Ajouter un évènement"),
content: StatefulBuilder(builder: (
BuildContext context,
StateSetter setState,
) {
return SingleChildScrollView(
child: Form(
key: _formKey,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(children: [
Expanded(
child: DropdownButtonFormField(
decoration: InputDecoration(
hoverColor: Colors.white,
//contentPadding: EdgeInsets.only(left: 10, right: 15, top: 15),
labelText: 'Type',
alignLabelWithHint: true,
labelStyle: TextStyle(
color: kPrimaryColor,
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.grey),
),
),
dropdownColor: Colors.white,
value: status,
items: <DropdownMenuItem>[
DropdownMenuItem(
// value: 'videnge',
value: 0,
child: InkWell(
child: Text('videnge'),
hoverColor: Colors.indigo,
),
),
DropdownMenuItem(
// value: 'visite technique',
value: 1,
child: Text('visite technique'),
),
DropdownMenuItem(
// value: 'assurance véhicule',
value: 2,
child: Text('assurance véhicule'),
),
DropdownMenuItem(
// value: 'autre',
value: 3,
child: Text('autre'),
),
],
onChanged: (value) {
setState(() {
status = value;
});
},
)),
]),
if (status == 1) visiTechniqueDropdown(),
]),
));
}),
actions: <Widget>[
TextButton(
child: Text(
"Enregistrer",
style: TextStyle(
color: Colors.red, fontWeight: FontWeight.bold),
),
onPressed: () {
if (status == null) return;
setState(() {
if (_events[_controller.selectedDay] != null) {
_events[_controller.selectedDay].add(status);
} else {
_events[_controller.selectedDay] = [status];
}
prefs.setString(
"events", json.encode(encodeMap(_events)));
status;
setRevision();
_KilometrageController.clear();
_eventController.clear();
_EmplacementController.clear();
_DateController.clear();
_repeat_revisionController.clear();
_revision_agenceController.clear();
_Kilometrage_revisionController.clear();
Navigator.of(context).pop();
// Navigator.pop(context);
});
},
),
new TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Retour'),
),
],
));
}
void setRevision() async {
print("hello");
if (_formKey.currentState.validate()) {
String kilometrage_pour_vidange = _KilometrageController.text;
String revision_type = status.toString();
String revision_title = _eventController.text;
String revision_location = _EmplacementController.text;
String revision_date = _DateController.text;
String repeat_revision = _repeat_revisionController.text;
String revision_agence = _revision_agenceController.text;
String kilometrage_revision = _Kilometrage_revisionController.text;
revisionApi
.setRevision(
revision_type,
revision_title,
revision_date,
revision_location,
kilometrage_pour_vidange,
repeat_revision,
revision_agence,
kilometrage_revision,
)
.then((data) {
if (data != null) {
Navigator.pop(context);
Navigator.of(context).pop();
Navigator.push(
context, MaterialPageRoute(builder: (context) => Revision()));
}
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(data)));
}).catchError((error) {
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text(error.toString())));
});
setState(() {});
}
}
Widget visiTechniqueDropdown() {
return Column(mainAxisSize: MainAxisSize.min, children: [
Row(
children: [
Flexible(
child: TextFormField(
onFieldSubmitted: (_) => FocusScope.of(context).nextFocus(),
validator: (value) {
if (value.isEmpty) {
return 'Password is required';
}
return null;
},
controller: _DateController,
cursorColor: kPrimaryColor,
decoration: InputDecoration(
labelText: 'Date',
alignLabelWithHint: true,
labelStyle: TextStyle(
color: kPrimaryColor,
),
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.grey),
How i can set the validator correctly ?
This is for you. Thanks and enjoy
// Create a corresponding State class.
// This class holds data related to the form.
class MyFormState extends State<MyForm> {
// Create a global key that uniquely identifies the Form widget
// and allows validation of the form.
//
// Note: This is a GlobalKey<FormState>,
// not a GlobalKey<MyFormState>.
final _formKey = GlobalKey<FormState>();
#override
Widget build(BuildContext context) {
// Build a Form widget using the _formKey created above.
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
// The validator receives the text that the user has entered.
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please enter some text';
}
return null;
},
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: ElevatedButton(
onPressed: () {
// Validate returns true if the form is valid, or false otherwise.
if (_formKey.currentState!.validate()) {
// If the form is valid, display a snackbar. In the real world,
// you'd often call a server or save the information in a database.
// sendData();
ScaffoldMessenger.of(context)
.showSnackBar(SnackBar(content: Text('Processing Data')));
}
},
child: Text('Submit'),
),
),
],
),
);
}
}

Not able to change a value in one page with respect to the value from another page in flutter

i want to change the indexvalue (pictogramindex) of one page when we click nextbutton on another screen.I will explain briefly , I have 2 screens in my scenario the first screen contains an image and it's name , a textfield and nextbutton (i have provided a dummy data contains a list of image and it's names) the logic behind this is , when we complete the textfield box and click next button(after validate) the textfield value checks with the correctvalue which i was given in the dummy data and show it's synonym which also provided. when we click the next button we will go to another page which contains the correct answer(passed from first page) and a textfield in this the user can write about the correct answer ( validated) when click next button in this page (till this my applicationworks perfectly) i want to load the first page with it's index updated (+1) which i initialised as 0 (var pictogramindex=0). But in my case when coming back to first page the index is not updating it will automatically stores the initialised value. what i want is i want to update index on the first page when i click next button in the Second page .
my source code of first screen is shown here
class Pictogramscreen extends StatefulWidget {
final int length;
const Pictogramscreen({Key key, this.length}) : super(key: key);
#override
_PictogramscreenState createState() => _PictogramscreenState();
}
class _PictogramscreenState extends State<Pictogramscreen> {
#override
final _Key = GlobalKey<FormState>();
Color defaultcolor = Colors.blue[50];
Color trueColor = Colors.green;
Color falseColor = Colors.red;
Widget defcorrect = Text('');
var pictogramindex = 0;
TextEditingController usertitleInput = TextEditingController();
nextPictogram() {
setState(() {
pictogramindex++;
});
}
fillColor() {
setState(() {
usertitleInput.text == pictdata[pictogramindex]['pictcorrectword']
? defaultcolor = trueColor
: defaultcolor = falseColor;
});
}
correctText() {
setState(() {
usertitleInput.text == pictdata[pictogramindex]['pictcorrectword']
? defcorrect = Text(pictdata[pictogramindex]['pictsynonym'])
: defcorrect = Text(pictdata[pictogramindex]['pictcorrectword']);
});
}
reset() {
setState(() {
defaultcolor = Colors.blue[50];
defcorrect = Text('');
usertitleInput.clear();
});
}
void description(BuildContext ctx) {
Navigator.of(context).pushNamed('/user-description', arguments: {
'id': pictdata[pictogramindex]['pictid'],
'word': pictdata[pictogramindex]['pictcorrectword']
});
}
Widget build(BuildContext context) {
int length = pictdata.length;
return Scaffold(
body: pictogramindex < pictdata.length
? ListView(
children: <Widget>[
Container(
margin: EdgeInsets.only(top: 20),
padding: EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Card(
margin: EdgeInsets.only(top: 20),
child: Image.network(
pictdata[pictogramindex]['pictimg']),
),
SizedBox(
height: 10,
),
Text(
pictdata[pictogramindex]['pictword'],
style: TextStyle(
fontSize: 25,
),
),
SizedBox(
height: 10,
),
//Card(
//color: Colors.blue,
// child: TextField(
// decoration: InputDecoration.collapsed(
// hintText: 'type here'),
//textAlign: TextAlign.center,
// onSubmitted: (value) {
// usertitleInput = value;
// print(usertitleInput);
// },
// ),
//),
Form(
key: _Key,
child: TextFormField(
controller: usertitleInput,
validator: (usertitleInput) {
if (usertitleInput.isEmpty) {
return 'Answer cannot be empty';
} else {
return null;
}
},
textAlign: TextAlign.center,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide:
BorderSide(color: Colors.blueAccent),
borderRadius: BorderRadius.all(
Radius.circular(15),
)),
labelText: 'Type your Answer',
filled: true,
fillColor: defaultcolor,
),
onFieldSubmitted: (value) {
usertitleInput.text = value;
fillColor();
correctText();
print(usertitleInput.text);
}),
),
SizedBox(
height: 10,
),
defcorrect,
SizedBox(
height: 10,
),
RaisedButton(
onPressed: () {
if (_Key.currentState.validate()) {
description(context);
// nextPictogram();
reset();
}
//
//if (_Key.currentState.validate() == correctText()) {
// nextPictogram;
// }
},
child: Text('Next'),
)
],
),
),
],
)
: Center(
child: Text('completed'),
));
}
}
my source code of the second screen is show here
class Userinputscreen extends StatefulWidget {
final String id;
final String word;
const Userinputscreen({Key key, this.id, this.word}) : super(key: key);
#override
_UserinputscreenState createState() => _UserinputscreenState();
}
class _UserinputscreenState extends State<Userinputscreen> {
final _Keey = GlobalKey<FormState>();
TextEditingController userdescription = TextEditingController();
var pictogramindex;
void nextpict(BuildContext context) {
Navigator.of(context).pushNamed('/main-screen');
}
// void nextpict(BuildContext context, int index) {
// Navigator.push(
// context,
// MaterialPageRoute(
// builder: (ctx) => Pictogramscreen(
// index: i = 0,
// )));
// }
#override
Widget build(BuildContext context) {
final routeArgs =
ModalRoute.of(context).settings.arguments as Map<String, String>;
final correctWord = routeArgs['word'];
return MaterialApp(
home: Scaffold(
body: ListView(children: <Widget>[
Padding(
padding: EdgeInsets.only(top: 50),
child: Center(
child: Container(
padding: EdgeInsets.all(20),
margin: EdgeInsets.only(top: 100),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
correctWord,
style: TextStyle(fontSize: 26),
),
SizedBox(
height: 10,
),
Form(
key: _Keey,
child: TextFormField(
controller: userdescription,
validator: (userdescription) {
if (userdescription.isEmpty) {
return 'Answer cannot be empty';
} else {
return null;
}
},
textAlign: TextAlign.center,
decoration: InputDecoration(
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueAccent),
borderRadius: BorderRadius.all(
Radius.circular(15),
)),
labelText: 'Type your Answer',
filled: true,
),
onFieldSubmitted: (value) {
userdescription.text = value;
print(userdescription.text);
}),
),
SizedBox(
height: 10,
),
RaisedButton(
onPressed: () {
if (_Keey.currentState.validate()) {
nextpict(context);
}
},
child: Text('Next'),
)
],
),
),
),
),
])),
);
}
}
If I get it right, you basically want to tell the initial page that it's state is updated(the index) elsewhere. You basically need to make your app "reactive".
As is said in Google Developers Tutorial:
One of the advantages of Flutter is that it uses reactive views, which you can take to the next level by also applying reactive principles to your app’s data model.
Use some sort of state management. You need to choose from and use either Bloc, InheritedWidget and InheritedModel, Provider(ScopedModel), or the like.
Check this article on flutter about state management, or this for a complete list of approaches

How to set the textfield value using Global key

What i am trying is to replicate "setText" in flutter without TextEditingController. Since I'm using FutureBuilder, i cannot go with manually updating state, thereby removing the choice of TextEditingController.
Bellow is the code for better understanding.
class DynamicFormBuilder {
GlobalKey<FormBuilderState> dynamicFormKey = GlobalKey<FormBuilderState>();
String getVariableData(String variable) {
return dynamicFormKey.currentState.fields[variable].currentState.value;
}
void setVariableData(String variable, String value) {
dynamicFormKey.currentState.fields[variable].currentState.didChange(value);
}
Widget workOnWidget(DynamicFormResponse widget) {
switch (widget.widget) {
case "text":
return Text(
widget.displayText,
style: TextStyle(
fontWeight: widget.style.fontWeight == "bold"
? FontWeight.bold
: FontWeight.normal,
fontSize: double.parse(widget.style.fontSize)),
);
case "editable":
return FormBuilderTextField(
attribute: widget.variable,
decoration: InputDecoration(labelText: widget.displayText),
onChanged: (val) {
if (widget.onChanged != null) {
onChangedFunctionMapper[widget.variable](val);
}
},
);
case "datepicker":
return FormBuilderDateTimePicker(
attribute: widget.variable,
inputType: InputType.date,
format: DateFormat("dd/MM/yyyy"),
decoration: InputDecoration(labelText: widget.displayText),
validators: [
FormBuilderValidators.required(),
],
);
case "divider":
return Container(
margin: EdgeInsets.fromLTRB(5, 10, 5, 10),
width: double.infinity,
height: 10,
color: accentColor,
);
case "dropdown":
return FormBuilderDropdown(
attribute: widget.variable,
items: convertDropdown(widget.options),
hint: Text(widget.hint),
decoration: InputDecoration(labelText: widget.displayText),
);
case "radioButton":
return FormBuilderRadioButton(
displayText: widget.displayText,
attribute: widget.variable,
isHorizontal: widget.isHorizontal,
onChanged: (val) {
if (val == "yes") {
visibilityMap["age"] = true;
} else {
visibilityMap["age"] = false;
}
},
options: widget.options
.map((lang) => FormBuilderFieldOption(value: lang))
.toList(growable: false),
);
default:
return Text("lol");
}
}
Widget buildForms(BuildContext context, Future<dynamic> fetchJSON) {
jsonData = new List();
dynamicFormKey = GlobalKey<FormBuilderState>();
accentColor = Theme.of(context).accentColor;
return FutureBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.none &&
snapshot.hasData == null) {
return Container(
child: Text("No Data got loaded"),
);
} else if (snapshot.connectionState == ConnectionState.done) {
for (int i = 0; i < snapshot.data.length; i++) {
jsonData.add(DynamicFormResponse.fromJson(snapshot.data[i]));
}
return ListView(
padding: EdgeInsets.all(10),
children: <Widget>[
FormBuilder(
key: dynamicFormKey,
autovalidate: false,
child: Card(
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: jsonData.map<Widget>((widget) {
print(widget.widget);
return workOnWidget(widget);
}).toList(),
),
),
),
),
],
);
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
future: fetchJSON,
);
}
}
So here when i do updates using setVariableData(variable, data), the variable in state is getting updated, but the same is not getting reflected in TextFields.
First of all, your question is quite confusing. However, I guess, you are looking for something to set the value to some xyz variable when you submit the data, right?
You can do this by two ways, these are:
Using onSubmitted Property: This gives the value when the user is done editing the value in the textfield
Using TextEditingController: Controls the text being edited.
Code using TextEditingController:
TextEditingController _controller = new TextEditingController();
TextField(
controller: _controller
)
//suppose you have a button which will print the data of the textfield for on onPressed
RaisedButton(
onPressed: () {
//this will print the value you've entered into the textfield
print(this._controller.text)
//change the value using setState here
setState((){
value_to_be_changed_variable = this._controller.text
})
},
child: const Text('Submit', style: TextStyle(fontSize: 20))
)
Code using onSubmitted Property:
TextField(
onSubmitted: (value) {
//do the operation here with the help of setState()
setState((){
variable_value_to_be_changed = value
})
}
)
I hope that'd suffice your needs. For more info read about Textfield Flutter Class thoroughly. It will help in you in many ways