'Flutter setState not updating a particular widget
I am using multi_select_flutter to show multi chips in my flutter project. However, am trying to add more items to the chip with data loaded from my api while the user is searching but it doesn't update the state of the multi chip widget. Here is my full code.
Even when I hot reload, it does not update itself. The only way I can manually enforce a refresh update is to re-ad the widget and reload consecutively. Any information as to why this strange behavior happens?
class MultiChoiceComponent extends StatefulWidget {
const MultiChoiceComponent({Key key}) : super(key: key);
@override
_MultiChoiceComponentState createState() => _MultiChoiceComponentState();
}
class _MultiChoiceComponentState extends State<MultiChoiceComponent> {
ApiMethods apiMethods;
TextEditingController searchController = TextEditingController();
List<MultiSelectItem<dynamic>> labels = [];
final TextEditingController textEditingController = TextEditingController();
@override
void initState() {
// TODO: implement initState
super.initState();
apiMethods = new ApiMethods(context: context);
}
@override
Widget build(BuildContext context) {
return ListView(
shrinkWrap: true,
children: [
Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Text(
'Search and select as many symptoms been experienced, it helps with a more accurate diagnosis',
textAlign: TextAlign.start,
style: TextStyle(
fontSize: 14,
height: 1.8,
fontWeight: FontWeight.w400,
fontFamily: 'Euclid',
color: AppColors.grey1,
),
),
),
SizedBox(
height: 20,
),
Container(
padding: EdgeInsets.symmetric(horizontal: 16,),
// height: maxLines * 50.0,
child: TextField(
controller: textEditingController,
cursorColor: Colors.black26,
onChanged: (val){
if(val!=""){
searchSymptoms(val);
}
},
decoration: InputDecoration(
filled: true,
hintStyle: TextStyle(
fontSize: 14,
height: 1.6,
fontWeight: FontWeight.w400,
fontFamily: 'Euclid',
color: AppColors.grey1,
),
hintText: "Search for a symptom/illness",
fillColor: Colors.white,
contentPadding: EdgeInsets.symmetric(horizontal: 16.0, vertical: 14),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0),
borderSide: BorderSide(color: AppColors.textColor.withOpacity(0.5)),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0),
borderSide: BorderSide(color: AppColors.textColor.withOpacity(0.5)),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12.0),
borderSide: BorderSide(color: AppColors.textColor.withOpacity(0.5)),
)),
),
),
MultiSelectChipField(
scroll: false,
decoration: BoxDecoration(
border: Border.all(color: Colors.transparent, width: 1.8),
),
showHeader: false,
selectedTextStyle: TextStyle(
fontSize: 12.5,
height: 1.8,
fontWeight: FontWeight.w400,
fontFamily: 'Euclid',
color: Colors.white,
),
chipShape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
selectedChipColor: AppColors.customGreen,
chipColor: Colors.white,
textStyle: TextStyle(
fontSize: 12.5,
height: 1.8,
fontWeight: FontWeight.w400,
fontFamily: 'Euclid',
color: AppColors.textColor,
),
items: labels,
onTap: (value) {
///add symptoms to list
print(value);
selectedSymptoms = value as List<Conditions>;
},
),
],
);
}
Future<void> searchSymptoms(String searchQuery) async {
List<dynamic> _data = await apiMethods.searchConditions(symptomCheckerAge, searchQuery);
conditions = Conditions.fromJsonList(_data);
labels = conditions.map((e) => MultiSelectItem(e, e.label)).toList();
setState(() {});
}
}
Solution 1:[1]
Can you share the full code.. like the part where you have declared variables like labels and conditions. You need to make sure that these variables are not final firstly and that these are using the late keyword or something like List? labels. If there's any other problem kindly share the whole code of this stateful class
**EDIT
So I tried this given Chip Widget with custom data and it is working properly.. Meaning the items that i am adding on pressed are being added to the new list. Take a look and try out the few changes and see if that works for you
class _MyHomePageState extends State<MyHomePage> {
static List<Animal> _animals = [
Animal(id: 1, name: "Lion"),
Animal(id: 2, name: "Flamingo"),
Animal(id: 3, name: "Hippo"),
Animal(id: 4, name: "Horse"),
Animal(id: 5, name: "Tiger"),
Animal(id: 6, name: "Penguin"),
Animal(id: 7, name: "Spider"),
Animal(id: 8, name: "Snake"),
Animal(id: 9, name: "Bear"),
Animal(id: 10, name: "Beaver"),
Animal(id: 11, name: "Cat"),
Animal(id: 12, name: "Fish"),
Animal(id: 13, name: "Rabbit"),
];
dynamic _items = _animals
.map((animal) => MultiSelectItem<Animal>(animal, animal.name))
.toList();
@override
Widget build(BuildContext context) {
return new Scaffold(
backgroundColor: Colors.white,
appBar: new AppBar(
title: new Text('Hello'),
),
body: ListView(
scrollDirection: Axis.vertical,
physics: NeverScrollableScrollPhysics(),
children: [
Container(
child: MultiSelectChipField(
scroll: false,
decoration: BoxDecoration(
border: Border.all(color: Colors.transparent, width: 1.8),
),
showHeader: false,
selectedTextStyle: TextStyle(
fontSize: 12.5,
height: 1.8,
fontWeight: FontWeight.w400,
color: Colors.blue,
),
chipShape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
selectedChipColor: Colors.green,
chipColor: Colors.yellow,
textStyle: TextStyle(
fontSize: 12.5,
height: 1.8,
fontWeight: FontWeight.w400,
color: Colors.black,
),
items: _items,
onTap: (value) {
///add symptoms to list
print(value);
},
),
),
ElevatedButton(
onPressed: () {
_items.add(MultiSelectItem<Animal>(
Animal(id: 27, name: 'name'), 'new'));
setState(() {});
},
child: Text('Add'))
],
),
);
}
}
class Animal {
final int id;
final String name;
Animal({
required this.id,
required this.name,
});
}
Solution 2:[2]
Try this
Future<void> searchSymptoms(String searchQuery) async {
List<dynamic> _data = await apiMethods.searchConditions(symptomCheckerAge, searchQuery);
conditions = Conditions.fromJsonList(_data);
labels = conditions.map((e) => MultiSelectItem(e, e.label)).toList();
setState(() {});
}
Solution 3:[3]
I was also struggling with hot reload of the MultiSelectChipField
and the solution was to update the globalkey during reload.
Pseudo code:
late var _multiSelectKey;
late List<MultiSelectItem<SomeClass?>>? _items;
@override
void initState() {
_items = null;
}
void reloadChip()
{
_multiSelectKey = GlobalKey<FormFieldState>();
_items = getItemsFromSomeWhere();
}
In scaffold the chip has these params
MultiSelectChipField<SomeClass?>(
initialValue: getSelected(),
key: _multiSelectKey,
title: const Text("Title"),
items: _items!,
onTap: (items) async { },
},
),
When function reloadChip()
is called and a setState(() {});
is triggered the MultiSelectChipField
will update.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Varun Kumar |
Solution 3 | Large |