Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Getx is not working properly with FutureBuilder for update list

I'm using the Getx controller in my project. I have create the controller for FutureBuilder for displaying list but .Obs is not set on Future Function. I'm sharing the code.

class PPHomeController extends GetxController {
  Future<List<PPProductRenterModel>> listNearProduct;

  // i want to set .Obs end of the "listNearProduct" but it's not working because of Future.  

  FetchNearProductList({@required int price}) async {
      listNearProduct = CallGetNearProducts();// Http API Result
  }
} 



{
  PPHomeController _homeController = Get.put(PPHomeController());

  Widget mainProductListView() {
return FutureBuilder<List<PPProductRenterModel>>
  (builder: (context, AsyncSnapshot<List<PPProductRenterModel>> projectSnap){
    if(!projectSnap.hasData){
      if(projectSnap.connectionState == ConnectionState.waiting){
        return Container(
          child: Loading(),
        );
      }
    }
   
    return ListView.builder(
        itemCount: projectSnap.data.length,
        itemBuilder: (context, index) {

          PPProductRenterModel model = projectSnap.data[index];
          PPPrint(tag: "CheckId",value: model.productId);
          return ProductMainItemRow(model);
        });

},
  future: _homeController.listNearProduct,);
like image 552
Alpit Panchal Avatar asked Nov 11 '20 09:11

Alpit Panchal


People also ask

How do I use Getstate instead of GetX?

The Getx state manager is easier than using setState. You just need to add a ". obs" at the end of your variable, and wrap the widget you want to change within a Obx().

How do I manually dispose of GetX controller?

Move Get. put from being a field of MainScreen to inside its build() method. The Controller can then be disposed when MainScreen is popped.

What is bindings GetX?

The Binding class is a class that will decouple dependency injection, while "binding" routes to the state manager and dependency manager. This allows Get to know which screen is being displayed when a particular controller is used and to know where and how to dispose of it.

What is a FutureBuilder?

FutureBuilder is a Widget that will help you to execute some asynchronous function and based on that function's result your UI will update. FutureBuilder is Stateful by nature i.e it maintains its own state as we do in StatefulWidgets.


Video Answer


2 Answers

There is a cleaner way for implementing List in GetX without worrying about Type-Casting:

Instantiate it:

final myList = [].obs;

Assign it:

myList.assignAll( listOfAnyType );

(Reference) Flutter error when using List.value :

'value' is deprecated and shouldn't be used. List.value is deprecated. use [yourList.assignAll(newList)]. Try replacing the use of the deprecated member with the replacement.


Detailed code example

ProductController.dart

class ProductController extends GetxController {
  final productList = [].obs;

  @override
  void onInit() {
    fetchProducts();
    super.onInit();
  }

  void fetchProducts() async {
    var products = await HttpServices.fetchProducts();
    if (products != null) {
      productList.assignAll(products);
    }
  }
}

HttpServices.dart

class HttpServices {
  static var client = http.Client();

  static Future<List<Product>> fetchProducts() async {
    var url = 'https://link_to_your_api';
    var response = await client.get(url);
    if (response.statusCode == 200) {
      return productFromJson(response.body);
    } else {
      return null;
    }
  }
}

product.dart

class Product {
  Product({
    this.id,
    this.brand,
    this.title,
    this.price,
    ....
  });
  ....
}
like image 111
Humayoun Alamgir Avatar answered Sep 24 '22 15:09

Humayoun Alamgir


Form the docs:

3 - The third, more practical, easier and preferred approach, just add .obs as a property of your value:

final items = <String>[].obs;

Following that instruction, this should work:

final listNearProduct = Future.value(<PPProductRenterModel>[]).obs;

E.g.:

// controller
final list = Future.value(<String>[]).obs;

@override
  void onInit() {
    super.onInit();
    fetchList();
}

Future<List<String>> callApi() async {
  await Future.delayed(Duration(seconds: 2));
  return ['test'];
}

void fetchList() async {
  list.value = callApi();
}


// screen
@override
Widget build(BuildContext context) {
  return GetX<Controller>(
    init: Controller(),
    builder: (controller) {
      return FutureBuilder<List<String>>(
        future: controller.list.value,
        builder: (context, snapshot) {
          if (snapshot.hasData) {
            print(snapshot.data[0]); // Output: test
            return Text(snapshot.data[0]);
          } else if (snapshot.hasError) {
            return Text("${snapshot.error}");
          }

          // By default, show a loading spinner.
          return CircularProgressIndicator();
        },
      );
    },
  );
};
like image 22
Matthias Avatar answered Sep 22 '22 15:09

Matthias