Reputation: 165
i'm trying to add data to flutter database using choice chips. Here is how it works: The user has to first of all choose whether the state of the operation is success or failure. Depending on his choice, another choice chips field will have dynamic values. And then the price will be calculated based on that. If it's success the price variable will have a defined value, if it's failure, it'll have zero for all the chips except 2 of them. Anyway, the problem here is that once I switch between success and failure, the value do not get updated unless I unselect and then select it again.
Here is my code where this logic is implemented:
Wrap(
runSpacing: spacing,
spacing: spacing,
children: choiceChipsInterventions
.map((cc) => ChoiceChip(
label: Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Container(
child: Align(
alignment: Alignment.center,
child: Text(cc.label)),
height: 30,
width: 100,
),
),
labelStyle: TextStyle(
color: Colors.white, fontWeight: FontWeight.bold),
onSelected: (isSelected) => setState(() {
intervention = cc.label;
if (etatLabel == "Succés") {
setState(() {
price = cc.prix;
});
} else if (etatLabel == "Echec") {
if (intervention == "SAV sans RDV" ||
intervention == "PP sans RDV") {
setState(() {
price = 25;
});
} else {
setState(() {
price = 0;
});
}
}
choiceChipsInterventions =
choiceChipsInterventions.map((otherChip) {
final newChip = otherChip.copy(
isSelected: false,
label: otherChip.label,
selectedColor: otherChip.selectedColor,
textColor: otherChip.textColor,
prix: otherChip.prix);
return cc == newChip
? newChip.copy(
isSelected: isSelected,
label: otherChip.label,
selectedColor: otherChip.selectedColor,
textColor: otherChip.textColor,
prix: otherChip.prix)
: newChip;
}).toList();
}),
selected: cc.isSelected,
selectedColor: etatLabel == "Echec"
? Color.fromARGB(255, 212, 9, 5)
: Colors.green,
backgroundColor: Color(0xFF473F97),
))
.toList(),
),
Noting that chips data is already defined in a separate file based on a chip model. Here is a screenshot that explains it better:
In this screenshot, I first selected success,then selected an intervention that has a value of 60€, after that I switched the state to failure (Echec), and the price still has 60€, it should have 0€! PS: As mentionned above, if I unselect and select again it will get 0€ as price!
I appreciate your help, thanks in advance!
Upvotes: 0
Views: 992
Reputation: 3540
As suggested avoid nested chips or something like. You may also consider using a ValueNotifier
to update chips bewteen each others (communication between widgets).
Here is a full working example based on what you want achieve : https://dartpad.dev/?id=8f2d7f9e7d43b450dcedbb1fb520118c
Hope this will help others too !
import 'package:flutter/material.dart';
void main() {
runApp(const MyHomePage(title: 'demo chips'));
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ValueNotifier<String?> _interventionStateNotifier = ValueNotifier<String?>(null);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MyOptions(notifier: _interventionStateNotifier),
const SizedBox(height: 25),
Interventions(notifier: _interventionStateNotifier)
],
),
),
),
);
}
}
class Intervention{
final String label;
final int price;
Intervention({required this.label, required this.price});
}
class Interventions extends StatefulWidget {
final ValueNotifier<String?> notifier;
final List<Intervention> interventions = [Intervention(label:"quick fix", price:30),
Intervention(label:"long fix", price:80)];
Interventions({Key? key, required this.notifier}) : super(key: key);
@override
State<Interventions> createState() => _InterventionsState();
}
class _InterventionsState extends State<Interventions> {
int? _value;
int? _priceSelected;
@override
Widget build(BuildContext context) {
return Column(
children: [
const Text('Select intervention'),
Wrap(
children: List<Widget>.generate(
widget.interventions.length,
(int index) {
return ChoiceChip(
label: Text('${widget.interventions[index].label} (${widget.interventions[index].price})'),
selected: _value == index,
onSelected: (bool selected) {
setState(() {
_value = selected ? index : null;
_priceSelected = widget.interventions[index].price;
});
},
);
},
).toList(),
),
ValueListenableBuilder<String?>( // listen state changes to update price
builder: (BuildContext context, String? state, Widget? child) {
switch(state){
case _MyOptionsState.failedString:
case null:
_priceSelected = 0;
break;
default:
if(_value != null) _priceSelected = widget.interventions[_value!].price;
}
return Text('Current price intervention : $_priceSelected');
},
valueListenable: widget.notifier,
),
],
);
}
}
class MyOptions extends StatefulWidget {
final ValueNotifier<String?> notifier;
const MyOptions({super.key, required this.notifier});
@override
State<MyOptions> createState() => _MyOptionsState();
}
class _MyOptionsState extends State<MyOptions> {
static const String failedString = "failed";
int? _value = 1;
List<String> items = ["success", failedString];
@override
Widget build(BuildContext context) {
return Column(
children: [
const Text("state"),
Wrap(
children: List<Widget>.generate(
items.length,
(int index) {
return ChoiceChip(
label: Text('Item ${items[index]}'),
selected: _value == index,
onSelected: (bool selected) {
setState(() {
_value = selected ? index : null;
});
widget.notifier.value = items[index];
},
);
},
).toList(),
),
],
);
}
}
Upvotes: 1