Home > Back-end >  Future Builder with for loop in flutter
Future Builder with for loop in flutter

Time:01-30

In my application, I have two future builders:

  CollectionReference stream = Firestore.instance.collection('users');
  List<String> myIDs =[];
  List <dynamic> mylist =[];
  List<String> myNames =[];
  String? userName;


Widget userValues() {
    return FutureBuilder(
      future: getrecords(),
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        if (snapshot.hasData &&
            snapshot.connectionState == ConnectionState.done) {
          return ListView.builder(
            shrinkWrap: true,
            itemCount: snapshot.data!.length,
            itemBuilder: (context, index) {
              return Text(snapshot.data?  [index] ?? "got null");
            },
          );
        }

        else {
          return CircularProgressIndicator();
        }
      },
    );

  }
..................

 Future getrecords() async{
    final data = await stream.get();
   
    mylist.addAll(data);
    mylist.forEach((element) {
      
      final String firstPartString = element.toString().split('{').first;

      final String id = firstPartString.split('/').last;

      myIDs.add(id.trim());

    });

    return(myIDs);
  }
....................
Widget Names() {

    return FutureBuilder(
      future: getNames(),
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        if (snapshot.hasData &&
            snapshot.connectionState == ConnectionState.done) {
          return ListView.builder(
            shrinkWrap: true,
            itemCount: snapshot.data!.length,
            itemBuilder: (context, index) {
              return Text(snapshot.data?[index] ?? "got null");
            },
          );
        }

        else {
          return CircularProgressIndicator();
        }
      },
    );
  }
............................
   Future getNames() async{

    for (var id in myIDs ){
      var names = stream.document(id).collection('userName').document('userName');
      var document = await names.get();
      userName = document['name'];
      myNames.add(userName!);
    }

    return(myNames);
  }

The first future (userValues) works fine, and I get the result just fine, but the other one with the for loop is not working properly and is not returning values until I hot reload, then a name will be added to the list, and so on with each hot reload.

What I want to achieve is to keep the loading indicator until the for loop is over, then build the screen.

UPDATE: If I could manage to make it so that the "Names" futurebuilder awaits for the userValues to complete before starting, then my problem would be solved, but what I realized is that it's taking the initial value of the return from "userValues," which is non, and using it to build.


Future getNames() async{
    await Future.delayed(const Duration(seconds: 2));
    for (var id in myIDs ){
      var names = stream.document(id).collection('userName').document('userName');
      var document = await names.get();
      userName = document['name'];
      myNames.add(userName!);
    }

    return(myNames);
  }

When I added this 2 seconds delay, it worked properly but is there any other way to make it wait for the first future to complete then start the second one?

CodePudding user response:

You can use the await keyword on the future returned from getrecords() to wait for the completion of getrecords() before starting the getNames() function:

Future getNames() async{
    await getrecords();

    for (var id in myIDs ){
      var names = stream.document(id).collection('userName').document('userName');
      var document = await names.get();
      userName = document['name'];
      myNames.add(userName!);
    }

    return(myNames);
  }
  • Related