Dmitri
Dmitri

Reputation: 11

Flutter GetX state management: how to update color attribute in ListView.builder and refresh the list?

I am trying to make an observable list. Specifically:

Show a list with names. The list is pulled from a list of objects containing a name key and a isSelected bool key.

  List<Student> students = [
    Student(name: "John", isSelected: false),
    Student(name: "Boris", isSelected: false),
    Student(name: "Max", isSelected: false)
  ];

The names are displayed in a ListView.builder. Clicking on the name should set the corresponding isSelected variable to true. This all works up to this point.

I want the list to refresh so that if isSelected is set to true, the item will show in a different color.

      child: Text(
        students[index].name,
        style: TextStyle(
          color: students[index].isSelected == true
              ? Colors.red
              : Colors.black87,
        ),
      ),

The problems I run into are:

  1. I get the error "Improper use of GetX. You should only use GetX or Obx for the specific widget that will be updated" no matter which widget I wrap into Obx. I have not included Obx in the code below as it leads to an error.

  2. I have read that lists are reactive but the items inside it are not and need to be made observable. I am not clear how this is done in this instance.

I paste the complete code below. Thank you for your help and apologies for asking something that's likely pretty basic.

import 'package:flutter/material.dart';
import 'package:get/get.dart';

void main() => runApp(testApp());

class Student {
  String name;
  bool isSelected;

  Student({required this.name, required this.isSelected});
}

class Controller extends GetxController {
  var students = <Student>[].obs;
}

class testApp extends StatelessWidget {
  @override
  List<Student> students = [
    Student(name: "John", isSelected: false),
    Student(name: "Boris", isSelected: false),
    Student(name: "Max", isSelected: false)
  ];

  Widget build(BuildContext context) {
    final controller = Get.put(Controller());

    return MaterialApp(
        home: Material(
      child: ListView.builder(
          itemCount: students.length,
          itemBuilder: (BuildContext ctxt, int index) {
            return InkWell(
              onTap: () {
                students[index].isSelected = true;
                // refresh does not work
                // controller.students.refresh();
              },
              child: Text(
                students[index].name,
                style: TextStyle(
                  color: students[index].isSelected == true
                      ? Colors.red
                      : Colors.black87,
                ),
              ),
            );
          }),
    ));
  }
}

Upvotes: 0

Views: 640

Answers (1)

Dmitri
Dmitri

Reputation: 11

The solution was to controller.students.refresh() the list. Posting the complete working code below.

import 'package:flutter/material.dart';
import 'package:get/get.dart';

void main() => runApp(testApp());

class Student {
  String name;
  bool isSelected;

  Student({required this.name, required this.isSelected});
}

class Controller extends GetxController {
  Rx<List<Student>> students = Rx<List<Student>>([
    Student(name: "John", isSelected: false),
    Student(name: "Boris", isSelected: false),
    Student(name: "Max", isSelected: false)
  ]);
}

class testApp extends StatelessWidget {
  @override
  //
  final controller = Get.put(Controller());

  Widget build(BuildContext context) {
    final controller = Get.put(Controller());

    return MaterialApp(
        home: Material(
      child: Obx(
        () => ListView.builder(
            itemCount: controller.students.value.length,
            itemBuilder: (BuildContext ctxt, int index) {
              return InkWell(
                onTap: () {
                  controller.students.value[index].isSelected = true;

                  controller.students.refresh();
                },
                child: Text(
                  controller.students.value[index].name,
                  // students[index].name,
                  style: TextStyle(
                    color: controller.students.value[index].isSelected == true
                        ? Colors.red
                        : Colors.black87,
                  ),
                ),
              );
            }),
      ),
    ));
  }
}

Upvotes: 1

Related Questions