0

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),
          ),
        );
      },
    );
  }
}

I tried the following code as suggested but did not work::

Suggestion code



import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';

import '../../services/auth/auth_service.dart';
import '../../services/cloud/cloud_chat.dart';
import '../../services/cloud/cloud_storage_constants.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"),
    );
  },
);
}}

Juan Casas
  • 268
  • 2
  • 13

1 Answers1

1

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.

  • I tried the code out but I had a small issue. I updated the question with ur code, and the output – Juan Casas Oct 23 '22 at 23:40
  • I tried to change the following snip but no luck either :( return FutureBuilder( future: cloudChats, I get the following error: The argument type 'Iterable' cant be assugbed to the parameter type 'Future?' – Juan Casas Oct 23 '22 at 23:46
  • Sorry dear for this , basically now the error is with userids because you want to call a future funtion for all the list items and you call this funtion again and again when you are using it inside listview builder , the solution of using future funtion in a widget is to use a future builder instead of using async / await funtion but it is my mistake that I forgot to focus you function complication.I will try to update the code and solve your problem and again sorry for that. – MOHAMMAD FUZAIL ZAMAN Oct 24 '22 at 19:16