Reputation: 113
I have three different TextFormFields
inside a Form
, but only two of them can be filled at the same time.
What I would like to achieve, is that whenerver two of them are filled, the other one should not be enabled.
They should be aware of changes in other fields at any time.
Below them is a RaisedButton
that should be enabled when this condition is met.
Moreover, I need to do some logic with their values when the said button is pressed.
This is what I have right now:
class LPFilterCalculator extends StatefulWidget {
@override
State<StatefulWidget> createState() => _LPFilterCalculatorState();
}
class _LPFilterCalculatorState extends State<LPFilterCalculator> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: PersistentAppBar("Low Pass Filter").build(context),
drawer: DrawerMenu(),
body: Column(
children: <Widget>[
LowPassInputForm(),
],
),
);
}
}
/// Inputform class for Calculators
class LowPassInputForm extends StatefulWidget {
@override
State<StatefulWidget> createState() => _LowPassInputFormState();
}
class _LowPassInputFormState extends State<LowPassInputForm> {
ValueNotifier<bool> pressed = ValueNotifier(false);
final _formKey = GlobalKey<FormState>();
final resistanceTextController = TextEditingController();
final capacitorTextController = TextEditingController();
final frequencyTextController = TextEditingController();
@override
Widget build(BuildContext context) {
print('state update');
return Form(
onChanged: () => {},
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Column(
children: <Widget>[
TextFormField(
controller: resistanceTextController,
inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly
],
keyboardType: TextInputType.number,
decoration:
const InputDecoration(hintText: 'Enter resistance value'),
),
TextFormField(
controller: capacitorTextController,
inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly
],
keyboardType: TextInputType.number,
decoration:
const InputDecoration(hintText: 'Enter capacitor value'),
),
TextFormField(
controller: frequencyTextController,
inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly
],
keyboardType: TextInputType.number,
decoration: const InputDecoration(
hintText: 'Enter desired cutoff frequency'),
),
RaisedButton(
elevation: 5.0,
onPressed: () {
calculateLowPass();
},
),
],
),
],
),
),
);
}
void calculateLowPass() {
var resistance = resistanceTextController.text;
var capacitor = capacitorTextController.text;
var frequency = frequencyTextController.text;
// do calculations
}
@override
void dispose() {
frequencyTextController.dispose();
super.dispose();
}
}
You should note I'm not really using some properties as well as functionalities of objects, as I'm not really sure which is the correct or best way to approach this in Flutter.
Any tips would be more than welcomed!
Upvotes: 0
Views: 1251
Reputation: 963
i am sure there are better way of doing it, but here is how i did it, i used the enabled
property on TextFormField
and created a method for each one that take the controller of the other two TextFormField
, i also created one for the button to check the all the text form fields, here is the full code:
/// Inputform class for Calculators
class LowPassInputForm extends StatefulWidget {
@override
State<StatefulWidget> createState() => _LowPassInputFormState();
}
class _LowPassInputFormState extends State<LowPassInputForm> {
ValueNotifier<bool> pressed = ValueNotifier(false);
final _formKey = GlobalKey<FormState>();
bool isEnabled = true;
final resistanceTextController = TextEditingController();
final capacitorTextController = TextEditingController();
final frequencyTextController = TextEditingController();
bool checkResistanceController() =>
frequencyTextController.text.isEmpty ||
capacitorTextController.text.isEmpty;
bool checkCapacitorController() =>
frequencyTextController.text.isEmpty ||
resistanceTextController.text.isEmpty;
bool checkFrequencyController() =>
resistanceTextController.text.isEmpty ||
capacitorTextController.text.isEmpty;
bool enableButton() =>
!checkFrequencyController() ||
!checkCapacitorController() ||
!checkResistanceController();
@override
Widget build(BuildContext context) {
print('state update');
return Form(
onChanged: () => setState(() {
checkResistanceController();
}),
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Column(
children: <Widget>[
TextFormField(
enabled: checkResistanceController(),
controller: resistanceTextController,
inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly
],
keyboardType: TextInputType.number,
decoration:
const InputDecoration(hintText: 'Enter resistance value'),
),
TextFormField(
enabled: checkCapacitorController(),
controller: capacitorTextController,
inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly
],
keyboardType: TextInputType.number,
decoration:
const InputDecoration(hintText: 'Enter capacitor value'),
),
TextFormField(
enabled: checkFrequencyController(),
controller: frequencyTextController,
inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly
],
keyboardType: TextInputType.number,
decoration: const InputDecoration(
hintText: 'Enter desired cutoff frequency'),
),
RaisedButton(
elevation: 5.0,
onPressed:
enableButton() ? () => calculateLowPass() : null),
],
),
],
),
),
);
}
void calculateLowPass() {
var resistance = resistanceTextController.text;
var capacitor = capacitorTextController.text;
var frequency = frequencyTextController.text;
// do calculations
}
@override
void dispose() {
frequencyTextController.dispose();
super.dispose();
}
}
Upvotes: 1
Reputation: 1436
You need to use the enabled
property on the TextFormField
and check whether the other two fields are empty. If any of the fields is empty then you enable the current field.
You could save your data in an Object
model:
class Object {
// for the sake of this example the fields here are strings, but in practice it's better to change them to double
String resistance;
String capacitor;
String frequency;
Object({
this.resistance = '',
this.capacitor = '',
this.frequency = '',
});
}
Your updated state looks like this with the added Object
instance:
class _LowPassInputFormState extends State<LowPassInputForm> {
final _formKey = GlobalKey<FormState>();
final resistanceTextController = TextEditingController();
final capacitorTextController = TextEditingController();
final frequencyTextController = TextEditingController();
Object data = Object();
@override
Widget build(BuildContext context) {
return Form(
onChanged: () => {},
key: _formKey,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: <Widget>[
Column(
children: <Widget>[
TextFormField(
enabled: data.capacitor.isEmpty || data.frequency.isEmpty,
onChanged: (val) => setState(() => data.resistance = val),
controller: resistanceTextController,
inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly
],
keyboardType: TextInputType.number,
decoration:
const InputDecoration(hintText: 'Enter resistance value'),
),
TextFormField(
enabled: data.resistance.isEmpty || data.frequency.isEmpty,
onChanged: (val) => setState(() => data.capacitor = val),
controller: capacitorTextController,
inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly
],
keyboardType: TextInputType.number,
decoration:
const InputDecoration(hintText: 'Enter capacitor value'),
),
TextFormField(
enabled: data.resistance.isEmpty || data.capacitor.isEmpty,
onChanged: (val) => setState(() => data.frequency = val),
controller: frequencyTextController,
inputFormatters: <TextInputFormatter>[
WhitelistingTextInputFormatter.digitsOnly
],
keyboardType: TextInputType.number,
decoration: const InputDecoration(
hintText: 'Enter desired cutoff frequency'),
),
RaisedButton(
elevation: 5.0,
onPressed: () {
calculateLowPass();
},
),
],
),
],
),
),
);
}
void calculateLowPass() {
// use data to do calculations
}
}
Upvotes: 0