Reputation: 1656
I'm using floatingActionButton
to increase TextForm Fields. i.e the fields increase by 1 once the button is tapped. The fields are actually increased on tap of the button but so confused on how to get values for each fields generated.
My problems:
When the user selects a value in the dropdown, all the values in the other generated dropdown fields changes to the new one. How do I solve this?
I'd like to add all the number value of the each of the generated Grade
field together and also add the value of each of the generated Course Unit
field together. i.e Add(sum) the value of all Grade
fields the user generated.
See my full code below:
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'My Grade Point',
theme: new ThemeData(primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _isLoading = false;
final formKey = new GlobalKey<FormState>();
final scaffoldKey = new GlobalKey<ScaffoldState>();
String _course;
String _grade;
String _unit;
String _mygp;
String _units;
String _totalgrade;
int counter = 1;
void _submit() {
final form = formKey.currentState;
if (form.validate()) {
setState(() => _totalgrade = _grade);
form.save();
}
}
Widget buildfields(int index) {
return new Column(
children: <Widget>[
new TextFormField(
onSaved: (String value) {
setState((){
_course = value;
});
},
validator: (val) {
return val.isEmpty
? "Enter Course Title $index"
: null;
},
decoration: new InputDecoration(labelText: "Course Title"),
),
new Row(
children: <Widget>[
new Expanded(
child: new TextFormField(
onSaved: (value) {
setState((){
_grade = value;
});
},
keyboardType: TextInputType.number,
decoration: new InputDecoration(labelText: "Grade"),
),
),
new Expanded(
child: new DropdownButton<String>(
onChanged: (String value) { setState((){
_unit = value;
});
},
hint: new Text('Course Unit'),
value: _unit,
items: <String>["1", "2", "3", "4", "5"].map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
),
),
],
),
],
);
}
@override
Widget build(BuildContext context) {
final Size screenSize = MediaQuery.of(context).size;
var loginBtn = new RaisedButton(
onPressed: _submit,
child: new Text("CALCULATE"),
color: Colors.primaries[0],
);
var showForm = new Container(
padding: new EdgeInsets.all(20.0),
child: new Column(
children: <Widget>[
new Expanded(child: new Form(
key: formKey,
child: new ListView.builder(
itemBuilder: (BuildContext context, int index) {
return buildfields(index); },
itemCount: counter,
scrollDirection: Axis.vertical,
),
),
),
_isLoading ? new CircularProgressIndicator() : loginBtn
],
),
);
return new Scaffold(
appBar: new AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: new Text(_totalgrade.toString()),
),
body: showForm,
floatingActionButton: new FloatingActionButton(
onPressed: () {
setState(() {
counter++;
});
},
child: new Icon(Icons.add),
),
);
}
}
Upvotes: 1
Views: 2914
Reputation: 10443
When the user selects a value in the dropdown, all the values in the other generated dropdown fields changes to the new one. How do I solve this?
The reason why DropdownButton
children in ListView updates synchronously is because it fetches all its value from the _unit
variable. I suggest using a List<Object>
to manage the data of ListView items.
i.e.
class Course {
var title;
var grade;
var unit;
}
...
List<Course> _listCourse = [];
I'd like to add all the number value of the each of the generated Grade field together and also add the value of each of the generated Course Unit field together. i.e Add(sum) the value of all Grade fields the user generated.
With ListView data being managed in List<Course>
, data inputted in the fields can be set in onChanged()
// Course Grade
TextFormField(
onChanged: (String value) {
setState(() {
_listCourse[index].grade = value;
});
},
)
and the values can be summed up with the help of a foreach
loop.
int sumGrade = 0;
_listCourse.forEach((course) {
// Add up all Course Grade
sumGrade += num.tryParse(course.grade);
});
Here's a complete working sample based from the snippet you've shared.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'My Grade Point',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: new MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class Course {
var title;
var grade;
var unit;
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool _isLoading = false;
final formKey = new GlobalKey<FormState>();
final scaffoldKey = new GlobalKey<ScaffoldState>();
String _course;
int _grade;
String _unit;
String _mygp;
String _units;
int _totalGrade;
int counter = 1;
List<Course> _listCourse = [];
@override
void initState() {
// Initialize empty List
_listCourse.add(Course());
super.initState();
}
void _submit() {
debugPrint('List Course Length: ${_listCourse.length}');
int sumGrade = 0;
_listCourse.forEach((course) {
debugPrint('Course Title: ${course.title}');
debugPrint('Course Grade: ${course.grade}');
// Add up all Course Grade
sumGrade += num.tryParse(course.grade);
debugPrint('Course Unit: ${course.unit}');
});
final form = formKey.currentState;
if (form.validate()) {
setState(() => _totalGrade = sumGrade);
form.save();
}
}
Widget buildField(int index) {
return new Column(
children: <Widget>[
new TextFormField(
onChanged: (String value) {
setState(() {
// _course = value;
_listCourse[index].title = value;
});
},
validator: (val) {
return val.isEmpty ? "Enter Course Title $index" : null;
},
decoration: new InputDecoration(labelText: "Course Title"),
),
new Row(
children: <Widget>[
new Expanded(
child: new TextFormField(
onChanged: (value) {
setState(() {
// _grade = value;
_listCourse[index].grade = value;
});
},
keyboardType: TextInputType.number,
decoration: new InputDecoration(labelText: "Grade"),
),
),
new Expanded(
child: new DropdownButton<String>(
onChanged: (String value) {
setState(() {
// _unit = value;
_listCourse[index].unit = value;
});
},
hint: new Text('Course Unit'),
value: _listCourse[index].unit,
items: <String>["1", "2", "3", "4", "5"].map((String value) {
return new DropdownMenuItem<String>(
value: value,
child: new Text(value),
);
}).toList(),
),
),
],
),
],
);
}
@override
Widget build(BuildContext context) {
final Size screenSize = MediaQuery.of(context).size;
var loginBtn = new RaisedButton(
onPressed: _submit,
child: new Text("CALCULATE"),
color: Colors.primaries[0],
);
var showForm = new Container(
padding: new EdgeInsets.all(20.0),
child: new Column(
children: <Widget>[
new Expanded(
child: new Form(
key: formKey,
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return buildField(index);
},
itemCount: counter,
scrollDirection: Axis.vertical,
),
),
),
_isLoading ? new CircularProgressIndicator() : loginBtn
],
),
);
return new Scaffold(
appBar: new AppBar(
title: new Text(_totalGrade.toString()),
),
body: showForm,
floatingActionButton: new FloatingActionButton(
onPressed: () {
setState(() {
// Add an empty Course object on the List
_listCourse.add(Course());
counter++;
});
},
child: new Icon(Icons.add),
),
);
}
}
Upvotes: 1