Search code examples
flutter-getx

LateError was thrown building Obx(has builder, dirty, state: _ObxState#17527): LateInitializationError: Field 'products' has not been initialized


I am using GetX. I need to display the data from database one the application open. But i get the Exception.

The following LateError was thrown building Obx(has builder, dirty, state: _ObxState#17527): LateInitializationError: Field 'products' has not been initialized.

Although, I have initialize the late variable inside onInit.

The Controller Code Is:

class HomeController extends GetxController {
  HomeController({required this.homeRepository});
  final IHomeRepository homeRepository;
  late Rx<Either<FireStoreServerFailures, List<Product>>> products; //=
  @override
  void onInit() async {
  products.value=  await fetchProductsFromDB();
    super.onInit();
  }
 Future<Either<FireStoreServerFailures, List<Product>>> fetchProductsFromDB() async {
    var _completer=Completer<Either<FireStoreServerFailures, List<Product>>>();
    homeRepository.fetchProducts().listen((event) {
      _completer.complete(event);
    });
    return await _completer.future;
  }
}

Home Page Where I Am Used The Late Variable's Code Is:

 Obx(
      () => GridView.builder(
          gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
            crossAxisCount: 2,
            childAspectRatio: 2 / 2,
          ),
          // TODO Deal with errors
          itemCount: controller.products.value.getOrElse(() => []).length,
          itemBuilder: (context, index) {
            return controller.products.value.fold(
                    (l) => Container(
                          height: double.infinity,
                          width: double.infinity,
                          color: Colors.red,
                          child: Text("Error ${l.msg}"),
                        ),
                    (r) => Card(
                          elevation: 2.0,
                          color: Colors.amber,
                          child: InkWell(
                            onTap: () async =>
                                await controller.goToMoreDetails(),
                            child: Stack(
                              fit: StackFit.expand,
                              clipBehavior: Clip.hardEdge,
                              children: [
                                Image.network(
                                  controller.products.value.fold(
                                      (l) => "",
                                      (r) => r[index]
                                          .pickedImages
                                          .getOrCrash()[0]),
                                  fit: BoxFit.fill,
                                  height: 200,
                                  width: 200,
                                ),
                                OverflowBox(
                                  minHeight: 30,
                                  alignment: Alignment.bottomCenter,
                                  child: Container(
                                    color: Colors.black.withOpacity(0.7),
                                    height: 30,
                                    width: double.infinity,
                                    child: Center(
                                      child: Text(
                                        "${controller.products.value.fold((l) => "", (r) => r[index].price.getOrCrash())}",
                                        style: const TextStyle(
                                          color: Colors.white,
                                        ),
                                      ),
                                    ),
                                  ),
                                ),
                              ],
                            ),
                          ),
                        )) ;
          }),
    );

Solution

  • You declared late Rx<Either<FireStoreServerFailures, List<Product>>> products; but did not initialise products anywhere. But on your onInit method you tried to access .value on products which is not yet initialised. Setting products.value is not initialising products. Also, your Obx widget tries to access the products field which is not initialised by the time it tries to access.

    What you should do is:

      final products = Rxn<Either<FireStoreServerFailures, List<Product>>>();
    

    And in your UI:

     Obx(
      () => controller.products.value == null? CircularProgressIndicator() : GridView.builder(......