This is an issue related to the getx in flutter. I have 2 controllers. ContractsController and NotificationController. In ContractsController I have put the value into observer variable by calling the Api request. What I want now is to get that variable's data in another controller - NotificationController. How to get that value using getx functions?
ContractsController
class ContractsController extends GetxController {
ExpiringContractRepository _expiringContractRepository;
final expiringContracts = <ExpiringContract>[].obs; // This is the value what I want in another controller
ContractsController() {
_expiringContractRepository = new ExpiringContractRepository();
}
@override
Future<void> onInit() async {
await refreshContracts();
super.onInit();
}
Future refreshContracts({bool showMessage}) async {
await getExpiringContracts();
if (showMessage == true) {
Get.showSnackbar(Ui.SuccessSnackBar(message: "List of expiring contracts refreshed successfully".tr));
}
}
Future getExpiringContracts() async {
try {
expiringContracts.value = await _expiringContractRepository.getAll(); // put the value from the api
} catch (e) {
Get.showSnackbar(Ui.ErrorSnackBar(message: e.toString()));
}
}
}
The expiringContracts is updated successfully with data after the api request. Now, I want to get that value in NotificationController
NotificationController
class NotificationsController extends GetxController {
final notifications = <Notification>[].obs;
ContractsController contractsController;
NotificationsController() {
}
@override
void onInit() async {
contractsController = Get.find<ContractsController>();
print(contractsController.expiringContracts); // This shows an empty list ?????
super.onInit();
}
}
CodePudding user response:
Overview
A couple solutions come to mind:
- pass the
expiringContracts
list as a constructor argument toNotificationsController
if you only need this done once at instantiation, or - use a GetX worker to update
NotificationsController
every timeexpiringContracts
is updated
The first solution isn't related to GetX, rather it's just async coordination between ContractsController
and NotificationsController
, so lets focus on the 2nd solution: GetX Workers.
Details
In NotificationsController
, create a method that will receive expiringContracts
.
Something like:
class NotificationsController extends GetxController {
void refreshContracts(List<ExpiringContract> contracts) {
// do something
}
}
Please note: none of this code is tested. I'm writing this purely in StackOverflow, so consider this pseudo-code.
In ContractsController
we'll supply the above callback method as a constructor arg:
In ContractsController
, something like:
class ContractsController {
final expiringContracts = <ExpiringContract>[].obs
final Function(List<ExpiringContract>) refreshContractsCallback;
ContractsController(this.refreshContractsCallback);
@override
void onInit() {
super.onInit();
refreshContracts(); // do your stuff after super.onInit
ever(expiringContracts, refreshContractsCallback);
// ↑ contracts → refreshContractsCallback(contracts)
// when expiringContracts updates, run callback with them
}
}
Here the GetX ever
worker takes the observable as first argument, and a function as 2nd argument. That function must take an argument of type that matches the observed variable, i.e. List<ExpiringContract>
, hence the Type of refreshContractsCallback
was defined as Function(List<ExpiringContract>)
.
Now whenever the observable expiringContracts
is updated in ContractsController
, refreshContractsCallback(contracts)
will be called, which supplies the list of expiring contracts to NotificationsController
via refreshContracts
.
Finally, when instantiating the two controllers inside the build()
method of your route/page:
NotificationsController nx = Get.put(NotificationsController());
ContractsController cx = Get.put(ContractsController(nx.refreshContracts));
Timeline of Events
NotificationsController
gets created asnx
.nx.onInit()
runs, slow call ofrefreshContracts()
startsContractsController
gets created, withnx.refreshContracts
callback- your page paints
nx
has no contracts data at this point, so you'll prob. need aFutureBuilder
or anObx
/GetX
StatelessWidget
that'll rebuild when data eventually arrives
- when
refreshContracts()
finishes,ever
worker runs, sending contracts tonx
nx.refreshContracts(contracts)
is run, doing something with contracts
Notes
- async/await was removed from
nx.onInit
ever
worker will run whenrefreshContract
finishes
CodePudding user response:
There were some powerful approaches in GetX. I solved this issue with Get.put and Get.find
Here is the code that I added.
ContractsController
class ContractsController extends GetxController {
ExpiringContractRepository _expiringContractRepository;
final expiringContracts = <ExpiringContract>[].obs; // This is the value what I want in another controller
ContractsController() {
_expiringContractRepository = new ExpiringContractRepository();
}
@override
Future<void> onInit() async {
await refreshContracts();
super.onInit();
}
Future refreshContracts({bool showMessage}) async {
await getExpiringContracts();
if (showMessage == true) {
Get.showSnackbar(Ui.SuccessSnackBar(message: "List of expiring contracts refreshed successfully".tr));
}
}
Future getExpiringContracts() async {
try {
expiringContracts.value = await _expiringContractRepository.getAll(); // put the value from the API
// ******************************** //
Get.put(ContractsController()); // Added here
} catch (e) {
Get.showSnackbar(Ui.ErrorSnackBar(message: e.toString()));
}
}
}
NotificationController
class NotificationsController extends GetxController {
final notifications = <Notification>[].obs;
ContractsController contractsController;
NotificationsController() {
}
@override
void onInit() async {
// ******************************** //
contractsController = Get.find<ContractsController>(); // Added here.
print(contractsController.expiringContracts); // This shows the updated value
super.onInit();
}
}
Finally, I have found that GetX is simple but powerful for state management in flutter. Thanks.