Home > Software design >  How to use a async function inside a ListView.builder?
How to use a async function inside a ListView.builder?

Time:10-23

Is there anyway to get a future when displaying a list? I have list with two user id's ( one of them is the userlogged in, the other one is the user to chat with ).

my goal is to get and display the other users name in the chat.

the issue I am running into, is that you cant do async functions within the list

how can i fix this?

error image


typedef JobCallback = void Function(CloudChat job);

class ChatsListWidget extends StatelessWidget {
  final Iterable<CloudChat> cloudChats; // list of jobs
  final JobCallback onDeleteJob;
  final JobCallback onTap;
  String get userId => AuthService.firebase().currentUser!.id;

  const ChatsListWidget({
    Key? key,
    required this.cloudChats,
    required this.onDeleteJob,
    required this.onTap,
  }) : super(key: key);

  Future getOtherUsersName(userIdsArr) async {
    String? otherUserInChatId;
    for (var _userId in userIdsArr) {
      if (_userId != userId) {
        otherUserInChatId = _userId;
      }
    }
    var userData = await FirebaseFirestore.instance
        .collection('user')
        .doc(otherUserInChatId)
        .get();

    return userData[userFirstNameColumn];
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      itemCount: cloudChats.length,
      itemBuilder: (context, index) {
        final job = cloudChats.elementAt(index);
        var otherUserName = await getOtherUsersName(job.userIdsArr);
;
        return ListTile(
          onTap: () {
            onTap(job);
          },
          title: Text(
            otherUserName,
            maxLines: 1,
            softWrap: true,
            overflow: TextOverflow.ellipsis,
          ),
          trailing: IconButton(
            onPressed: () async {
              //
            },
            icon: const Icon(Icons.delete),
          ),
        );
      },
    );
  }
}

CodePudding user response:

The simple and short answer is to use FutureBuilder which take future as named parameter and give you the result in builders parameters generally know as snapshot.

First of all wrap your list view with future builder :

  FutureBuilder(
      future: "you future funtion here",
      builder: (context, snapshot) {
        return ListView.builder(itemBuilder: itemBuilder);
      }
    )

now you can give future funtion , in your case it is

FutureBuilder(
  future: getOtherUsersName(job.userIdsArr),
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      return ListView.builder(
        itemCount: cloudChats.length,
        itemBuilder: (context, index) {
          final job = cloudChats.elementAt(index);

          return ListTile(
            onTap: () {
              onTap(job);
            },
            title: Text(
              otherUserName,
              maxLines: 1,
              softWrap: true,
              overflow: TextOverflow.ellipsis,
            ),
            trailing: IconButton(
              onPressed: () async {
                //
              },
              icon: const Icon(Icons.delete),
            ),
          );
        },
      );
    } else if (snapshot.connectionState == ConnectionState.waiting) {
      Center(
        child: CircularProgressIndicator(),
      );
    }
  
    return Center(
      child: Text("Empty"),
    );
  },
);

And remember to use snapshot if conditions for loading and empty data

complete code

import 'package:flutter/material.dart';
typedef JobCallback = void Function(CloudChat job);

class ChatsListWidget extends StatelessWidget {
final Iterable<CloudChat> cloudChats; // list of jobs
final JobCallback onDeleteJob;
final JobCallback onTap;
String get userId => AuthService.firebase().currentUser!.id;

const ChatsListWidget({
Key? key,
required this.cloudChats,
required this.onDeleteJob,
required this.onTap,
}) : super(key: key);

Future getOtherUsersName(userIdsArr) async {
String? otherUserInChatId;
for (var _userId in userIdsArr) {
  if (_userId != userId) {
    otherUserInChatId = _userId;
  }
}
var userData = await FirebaseFirestore.instance
    .collection('user')
    .doc(otherUserInChatId)
    .get();

return userData[userFirstNameColumn];
}

@override
Widget build(BuildContext context) {
return FutureBuilder(
  future: getOtherUsersName(job.userIdsArr),
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      return ListView.builder(
        itemCount: cloudChats.length,
        itemBuilder: (context, index) {
          final job = cloudChats.elementAt(index);

          return ListTile(
            onTap: () {
              onTap(job);
            },
            title: Text(
              otherUserName,
              maxLines: 1,
              softWrap: true,
              overflow: TextOverflow.ellipsis,
            ),
            trailing: IconButton(
              onPressed: () async {
                //
              },
              icon: const Icon(Icons.delete),
            ),
          );
        },
      );
    } else if (snapshot.connectionState == ConnectionState.waiting) {
      Center(
        child: CircularProgressIndicator(),
      );
    }

    return Center(
      child: Text("Empty"),
    );
  },
);
}}

HopeFully It will help you.

  • Related