'Obx ListView not updating after value changes
I am having a RxList
called todoData
. On the basis of this list, a ListView.builder
builds a list and in each list there is a button. When this button is clicked the done
field of the respective item is updated to either true
or false
. But, though the value is updated the ui is no changing.
Here's the list:
class StateController extends GetxController {
RxList<Todo> todoData = <Todo>[
Todo(
name: 'todo1',
done: true),
Todo(
name: 'todo2',
done: false),
Todo(
name: 'todo3',
done: true),
Todo(
name: 'todo4',
done: false),
Todo(
name: 'todo5',
done: false)
].obs;
}
Controller:
final StateController _controller = Get.find();
The update function:
void updateItem(Todo e) {
/* final int index = _controller.todoData.indexOf(e);
_controller.todoData[index].done = !e.done; */
_controller.todoData.firstWhere((Todo i) => i == e).done = !e.done;
_controller.refresh();
}
void deleteItem(Todo e) { //**this works**
final int index = _controller.todoData.indexOf(e);
_controller.todoData.removeAt(index);
}
Ui:
Obx(() => ListView.builder(
itemCount: _controller.todoData.length,
itemBuilder: (_, int i) => TodoItem(
item: _controller.todoData[i],
updateItem: () =>
updateItem(_controller.todoData[i]),
))
Any help is greatly appreciated!
Solution 1:[1]
Try calling refresh()
directly on the RxList
:
void updateItem(Todo e) {
/* final int index = _controller.todoData.indexOf(e);
_controller.todoData[index].done = !e.done; */
_controller.todoData.firstWhere((Todo i) => i == e).done = !e.done;
_controller.todoData.refresh(); // <- Here
}
Solution 2:[2]
i just modify some code of yours, just change the RxList to simple List and bool variable to RxBool and use obx on bool I'm sharing code
Your Model class and controller class
class StateController extends GetxController {
List<Todo> todoData = <Todo>[
Todo(name: 'todo1', done: true.obs),
Todo(name: 'todo2', done: false.obs),
Todo(name: 'todo3', done: true.obs),
Todo(name: 'todo4', done: false.obs),
Todo(name: 'todo5', done: false.obs)
].obs;
}
class Todo {
String? name;
RxBool? done;
Todo({this.name, this.done});
}
your UI Code
class TestClass extends StatelessWidget {
TestClass({Key? key}) : super(key: key);
final StateController _controller = Get.put(StateController());
void updateItem(Todo e) {
/* final int index = _controller.todoData.indexOf(e);
_controller.todoData[index].done = !e.done; */
_controller.todoData.firstWhere((Todo i) => i == e).done!.value =
!e.done!.value;
_controller.refresh();
}
void deleteItem(Todo e) {
//**this works**
final int index = _controller.todoData.indexOf(e);
_controller.todoData.removeAt(index);
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: ListView.builder(
itemCount: _controller.todoData.length,
itemBuilder: (_, int i) => TodoItem(
item: _controller.todoData[i],
updateItem: () => updateItem(_controller.todoData[i]),
)));
}
}
class TodoItem extends StatelessWidget {
TodoItem({Key? key, this.item, this.updateItem}) : super(key: key);
Todo? item;
VoidCallback? updateItem;
@override
Widget build(BuildContext context) {
return ListTile(
title: Text(
item!.name!,
style: TextStyle(color: Colors.black),
),
subtitle: GestureDetector(
onTap: updateItem,
child: Obx(() {
return Text(
item!.done!.value.toString(),
style: TextStyle(color: Colors.black),
);
}),
),
);
}
}
Solution 3:[3]
There are a few things you can do here to make your code work as expected.
First, you need to make sure that your Todo class implements the Equatable mixin. This will allow you to compare two Todo instances by value rather than by reference.
Second, you need to use the update() method on your RxList to update the value of the done field for the appropriate Todo instance.
Third, you need to call the refresh() method on your StateController after updating the done field so that the UI will be updated to reflect the new value.
Fourth, you should consider using the TodoItem widget's built-in updateItem() method rather than passing a callback to the widget. This will ensure that the TodoItem widget is updated correctly when the done field is changed.
Solution 4:[4]
Try calling update() function after update List.
void updateItem(Todo e) {
final int index = _controller.todoData.indexOf(e);
_controller.todoData[index].done = !e.done;
_controller.todoData.firstWhere((Todo i) => i == e).done = !e.done;
_controller.update(); // <- Here
}
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 | Suporte01 |
Solution 2 | Hamza Siddiqui |
Solution 3 | Carter McKay |
Solution 4 | Abdul Rahman Panhyar |