I am using GetX for the state management in flutter project. My problem is when I click on the checkbox it updates the state in controller but does not show the result in UI. In general the changed state should change the UI too. I am not sure what is the problem but I think there is a bug in using the observable variable in getx. How to solve this problem? If the post is not clear then please ask me.
This is the view.
class FilterBottomSheetWidget extends GetView<SearchController> {
@override
Widget build(BuildContext context) {
return Container(
height: Get.height - 90,
child: Stack(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 80),
child: Container(
padding: EdgeInsets.only(top: 20, bottom: 15, left: 4, right: 4),
child: controller.expiringContractStatus.isEmpty ? CircularLoadingWidget(height: 100)
: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: ExpansionTile(
title: Text("Contract Status".tr, style: Get.textTheme.bodyText2),
children: List.generate(controller.expiringContractStatus.length, (index) {
var _expiringContractStatus = controller.expiringContractStatus.elementAt(index);
return CheckboxListTile(
controlAffinity: ListTileControlAffinity.trailing,
value: _expiringContractStatus["isCheck"], // ************
onChanged: (value) {
controller.itemChange(value, index); // ************
controller.update();
},
title: Text(
_expiringContractStatus["title"],
style: Get.textTheme.bodyText1,
overflow: TextOverflow.fade,
softWrap: false,
maxLines: 1,
),
);
}),
initiallyExpanded: true,
);
}
)
),
),
// more widgets
],
),
);
}
}
This is SearchController.
class SearchController extends GetxController {
final expiringContractStatus = <Map>[
{
"title": "aaa",
"isCheck": false
},
{
"title": "bbb",
"isCheck": false
},
{
"title": "ccc",
"isCheck": false
}
].obs;
@override
void onInit() async {
await refreshSearch();
super.onInit();
}
void itemChange (bool value, int index) {
expiringContractStatus[index]["isCheck"] = value; // *************
update();
}
}
CodePudding user response:
Updated Answer:
If you tried wrapping an an Obx
and it didn't work, use GetBuilder<SearchController>
instead.
GetBuilder<SearchController>(
builder: (_) => controller.expiringContractStatus.isEmpty ? CircularLoadingWidget(height: 100)
: SingleChildScrollView(...))
When you call update()
it will trigger a rebuild no matter what, with the updated values. The only reason I can think of why Obx
didn't work is that perhaps when it comes to lists in only responds to an addition or removal of an item in the list and not a change in a property nested inside.
In general, you'll probably find that in most cases using an observable stream based variable is not really needed. GetBuilder
can handle most or all of what you need done unless you're doing something stream based (binding to an external Firebase collection for example). Nothing wrong with either, but GetBuilder
is the most performant option as streams by their nature are a bit more expensive.
Original answer:
I suggest you read the docs regarding proper usage before claiming there's a bug in someone else's code. That goes for any package that you're using.
It's stated all over the Readme
and in the basic counter app example that observable variables need to be placed in an Obx
widget, otherwise there's nothing triggering a rebuild based on the updated state of an observable GetX variable.
The child of your Container
should be
Obx(() => controller.expiringContractStatus.isEmpty ? CircularLoadingWidget(height: 100)
: SingleChildScrollView(...))