Search code examples
flutterrestmodel-view-controllerflutter-getx

How to use ListView with the data of REST API with Flutter using Obx?


import 'dart:convert';
import 'package:get/get.dart';
import '../../../functions/functions.dart';
import '../models/user_details_modal.dart';

class UserListController extends GetxController {
  var data = [];
  List<UserDetails> userDetails = <UserDetails>[].obs;
  // var userDetails = <UserDetails>[].obs;
  // RxList<UserDetails> userDetails = <UserDetails>[].obs;
  // RxList<UserDetails> userDetails = RxList();

  Future<void> fetchData() async {
    String apipage = "getData.php";
    Map mappeddata = {};
    final response = await sendServerData(apipage, mappeddata);

    if (response.statusCode == 200) {
      final responseBody = jsonDecode(response.body.toString());
      userDetails = userDetailsFromJson(json.encode(responseBody));
      print(userDetails);
      update();
    } else {
      Get.snackbar(
          'Server Connection Failed', 'Please try again after some time');
    }
  }

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

Above code is my controller,

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/user_list_controller.dart';
import '../models/user_details_modal.dart';

class UserListView extends GetView<UserListController> {
  @override
  final UserListController controller = Get.put(UserListController());
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('ListView'),
        centerTitle: true,
      ),
      body: Obx(
        () => controller.userDetails.isEmpty
            ? Center(
                child: Text("Loading data..."),
              )
            : ListView.builder(
                itemCount: controller.userDetails.length,
                itemBuilder: (context, index) {
                  final UserDetails item = controller.userDetails[index];
                  return buildListTile(item);
                },
              ),
      ),
    );
  }

  Widget buildListTile(UserDetails item) {
    print("userName: ${item.userName}"); 
    print("userEmail: ${item.userEmail}");
    return ListTile(
      title: Text(item.userName),
      subtitle: Text(item.userEmail),
      trailing: IconButton(
        icon: const Icon(Icons.edit),
        onPressed: () {},
      ),
    );
  }
}

This is my view,but it's throwing this error -

"[Get] the improper use of a GetX has been detected. You should only use GetX or Obx for the specific widget that will be updated. If you are seeing this error, you probably did not insert any observable variables into GetX/Obx or insert them outside the scope that GetX considers suitable for an update (example: GetX => HeavyWidget => variableObservable). If you need to update a parent widget and a child widget, wrap each one in an Obx/GetX."

i'm a beginner in flutter,so please help me to find the issue here.

I have updated the code,i made some changes in controller part declaring that List,now that prev issue is solved! But the problem is no data showing up on first load (using Get.to() to navigate to this from another page) but when i hot reload/reload this page it shows those data. What's the problem?


Solution

  • if you want to use reactive approach using Obx() or Getx(), you need to make your variables observable. You can do this simply by adding .obs to the variable. This makes your variables as Rx type. There are other ways to make your variables observable, but this is the simplest one.

    in the controller:

      var data = [].obs;
      List<UserDetails> userDetails = [].obs;
    

    Also, you don't need to use update() for this approach.

    And whenever you want to change the value or use it in your view you should access the value like this.

    in the view inside the Obx: ( in the code above, no need to use .value for the list)

    E.x)

    bool isLoading = controller.loading.value
    

    Hope this helped :)