Reputation: 768
I am trying to get data from a List
inside a GetxController
but it keeps returning null/Empty whenever I try to access it inside a GetBuilder even when I already assigned a value to it. Inside the GetxController
I can print out the value but when I want to use it it returns null/Empty
class BankController extends GetxController implements GetxService {
BankRepo bankRepo = BankRepo();
List<Bank> banks = [];
Future<void> getBanks() async {
ResponseModel response = await bankRepo.banks();
if (response.statusCode == 200) {
print(banks); // => []
banks = (response.data as List).map((e) => Bank.fromJson(e)).toList();
print(banks); // => [Instance of 'Bank', Instance of 'Bank', Instance of 'Bank', Instance of 'Bank', Instance of 'Bank', .....
update();
}
}
}
To Reproduce:
Steps to reproduce the behavior:
Call the getBanks function from BankController
Get banks from BankController in add_bank.dart eg BankController().banks
Print it to terminal, it returns empty List
Expected behavior:
After calling the getBanks
function from BankController
, a data is been assigned to List<Bank> banks = [];
, then I create a GetBuilder
inside add_bank.dart
to get the data inside List<Bank> banks = [];
and add them to my Dropdown. The dropdown will then display the list of all the banks.
Flutter Version:
Flutter Channel stable, v2.10.3
Getx Version:
get: ^4.6.5
Minimal reproduce code:
add_bank.dart
:
class AddBankView extends StatefulWidget {
const AddBankView({Key? key}) : super(key: key);
@override
State<AddBankView> createState() => _AddBankViewState();
}
class _AddBankViewState extends State<AddBankView> {
Bank selectedBank = Bank(name: "Select Bank", code: "");
@override
void initState() {
getBanks();
super.initState();
}
getBanks() async {
await BankController().getBanks();
BankController ctn = Get.find<BankController>();
print(ctn.banks); // => []
}
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: customAppbar("New Bank"),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(20.0),
child: GetBuilder<BankController>(
init: BankController(),
builder: (bankController) {
print(bankController.banks); // => []
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 50,
width: MediaQuery.of(context).size.width,
margin: const EdgeInsets.symmetric(vertical: 20),
child: DropdownButtonHideUnderline(
child: GFDropdown(
padding: const EdgeInsets.symmetric(vertical: 15),
borderRadius: BorderRadius.circular(5),
border: const BorderSide(
color: Colors.transparent,
width: 0,
style: BorderStyle.none),
dropdownButtonColor: Colors.transparent,
dropdownColor:
Theme.of(context).colorScheme.surface,
value: selectedBank,
icon: Icon(
IconlyBold.arrowDownCircle,
color: Theme.of(context).colorScheme.onSurface,
size: 22,
),
onChanged: (value) {
setState(() {
selectedBank = value as Bank;
});
},
items: bankController.banks
.map((Bank value) => DropdownMenuItem<Bank>(
value: value,
child: CustomText(value.name,
color: theme.secondary
.withOpacity(0.85)),
))
.toList(),
),
),
),
]);
}),
),
),
),
);
}
}
Bind Controllers in get_init.dart
:
initControllers() {
//Repositories
Get.lazyPut(() => BankRepo());
//Controllers
Get.lazyPut(() => BankController());
}
main.dart
:
void main() async {
initControllers();
runApp(const MyApp());
}
I ask you guys, how can I solve it. If you have any questions you can ask me.
Upvotes: 1
Views: 1031
Reputation: 644
There are two ways on doing this either you make it a service or a controller.
Service approach:
class BankService extends GetxService {}
main.dart file
await Get.putAsync<BankService>(() async => BankService());
add_bank_view.dart file
getBanks() async {
final ctn = Get.find<BankService>();
await ctn.getBanks();
print(ctn.banks); // => []
}
Controller approach:
class BankController extends GetxController {}
add_bank_view.dart file
final controller = Get.put(BankController());
getBanks() async {
await controller.getBanks();
print(controller.banks); // => []
}
Upvotes: 1
Reputation: 1201
Its a bit tricky when using Get.lazyPut
or Get.put
or instead Get.create
and depending on the case that you want it to act. Like Get.lazyPut
will not create the instance at the time, and will create it when you call Get.find
.
And in your case, this is the code from your question.
getBanks() async {
await BankController().getBanks();
BankController ctn = Get.find<BankController>();
print(ctn.banks); // => []
}
when you call await BankController().getBanks();
you literally create a new instance of BankController
using its constructor. and then on the line below, you create another instance of BankController
but using the GetX dependency injector (lazyPut
factory). So the instance ctn
and the instance created in this BankController().getBanks()
is completely different instance. and obviously will produce empty banks.
Get.lazyPut, or Get.put didn't simply make all of the class become singleton, you have to call Get.find
and use the instance from it to make it act as a single instance.
So, in conclusion, your code should be like this:
BankController ctn = Get.find<BankController>();
await ctn.getBanks();
print(ctn.banks);
More detail about the difference between put, lazyPut, and create can be found here:
Upvotes: 2
Reputation: 202
Have you used BankController in any other page?
If not, use Get.put instead of Get.find :-
final BankController bankControl = Get.put(BankController());
Upvotes: 1