Search code examples
flutterflutter-providerflutter-getx

Moving from Provider to GetX and cannot Get.find the correct Controller


I'm trying to move from Provider to GetX and am stuck on how GetX.find() works.

We have a restaurant app with a few tables. Below is the narrowed down view of my old Provider code showing just the staff table and VIP table. You click on the "Seat" button to mark the table as seated.:

  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Restaurant',
      home: Column(children: [
        ChangeNotifierProvider<Table>( //Provider
          create: (_) => Table("Staff"),  //create controller
          child: Builder(builder: (context) {
            return Column(children: [
              Text("Staff seated: ${context.watch<Table>().seated}"),  //consume changes
              ElevatedButton(
                  child: const Text("Seat Staff"),
                  onPressed: () {
                    context.read<Table>().toggleSeated();  //call controller
                  }),
            ]);
          }),
        ),
        ChangeNotifierProvider<Table>(. //Provider
            create: (_) => Table("VIP"),  //create controller
            child: Builder(
              builder: (context) {
                return Column(children: [
                  Text("VIP seated: ${context.watch<Table>().seated}"),  //consume changes
                  ElevatedButton(
                      child: const Text("Seat VIP"),
                      onPressed: () {
                        context.read<Table>().toggleSeated();  //call controller
                      }),
                ]);
              },
            )),
      ]),
    );
  }
}

and associated narrowed down controller:

class Table extends ChangeNotifier {
  final String name;
  int chairs = 0;
  bool seated = false;

  Table(this.name);

  toggleSeated() {
    seated = !seated;
    notifyListeners();  //notify providers
  }
}

Now here is the GetX code (which compiles fine) but I tried t.toggle and Get.find<Table>().toggle and both functions toggle both tables at the same time. In the old code they toggled the tables individually:

  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Restaurant',
        home: Column(
          children: [
            GetBuilder(  //GetX
              init: Table("Staff"),  //create controller
              builder: (Table t) {
                return Column(children: [
                  Text("Staff seated: ${t.seated}"),  //consume changes
                  ElevatedButton(
                    child: const Text("Seat Staff"),
                    onPressed: () {
                      //I've tried Get.find here
                      Get.find<Table>().toggleSeated();  //call controller
                    },
                  ),
                ]);
              },
            ),
            GetBuilder(. //GetX
              init: Table("VIP"),  //create controller
              builder: (Table t) {
                return Column(children: [
                  Text("VIP seated: ${t.seated}"),  //consume changes
                  ElevatedButton(
                    child: const Text("Seat VIP"),
                    onPressed: () {
                      //I've also tried directly using the controller
                      t.toggleSeated();  //call controller
                    },
                  ),
                ]);
              },
            ),
          ],
        ));
  }

and associated narrowed down controller:

class Table extends GetxController {
  final String name;
  int chairs = 0;
  bool seated = false;

  Table(this.name);

  toggleSeated() {
    seated = !seated;
    update();  //notify GetX
  }
}

In the Provider version I can interact with the tables individually but in the GetX version the button seems to act on all tables regardless of whether I use Get.find<Table>() or directly using the controller's t.toggle.


Solution

  • Controllers are created per type, but you can add 'tag' to create separate controllers. Also you need to add the controller to Get to have proper lifecycle:
    Get.put(Table())

    Like you have 'Staff' and 'VIP' you can pass that as a tag:
    Get.put(Table(), tag: 'Staff')

    GetX Controllers automatically released when the caller disposed so in your case when you leave the given page.

    You can find the 'Staff' Controller downstream with Get.find(tag:'Staff');