Kyle
Kyle

Reputation: 143

The operator '[]' isn't defined for the type 'Object' when trying to access data from futureBuilder

im trying to return two futures and getting the above error when trying to access the data within the returned snapshot.Specifically this line:

${snapshot.data!["firstName"]}

Any ideas as to the correct way to access this data, can't see any documentation anywhere defining this.

Code is as follows:

Widget build(BuildContext context) {
    return FutureBuilder(
      future: Future.wait([getData(), getMood()]),
      builder: (_, snapshot) {
        if (snapshot.hasData) {


          return Scaffold(
            appBar: AppBar(
              title: const Text('Display the Picture'),
              backgroundColor: kPrimaryColor,
            ),
            // The image is stored as a file on the device. Use the `Image.file`
            // constructor with the given path to display the image.
            body: Center(
              child: Column(
                children: <Widget>[
                  Padding(
                    padding: const EdgeInsets.fromLTRB(8.0, 20.0, 8.0, 8.0),
                    child: Column(
                      children: [
                        Center(
                          child: Text(
                            "${snapshot.data!["firstName"]} \n\n "
                            "We have predicted your mood as:\n\n "
                            "${snapshot.data!.data()!["mood"]}\n\n"
                            "Please select a reason associated to your mood",
                            style: const TextStyle(
                                color: Colors.black, fontSize: 15),
                            textAlign: TextAlign.center,
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          );
        } else {
          return CircularProgressIndicator();
        }
      },

    );
  }

  Future getData() async {
    var currentUser = FirebaseAuth.instance.currentUser;
   DocumentSnapshot q1 = await FirebaseFirestore.instance
        .collection('USER_TABLE')
        .doc(currentUser!.uid)
        .get();
    return q1;
  }

  Future getMood() async {
    var currentUser = FirebaseAuth.instance.currentUser;
    QuerySnapshot q2 = await FirebaseFirestore.instance
        .collection('userMood')
        .where('userId' == currentUser!.uid)
        .orderBy('createdAt',descending: true)
        .limit(1)
        .get();
    return q2;
  }

}

Thanks

EDIT

future: Future.wait([getData(), getMood()]),
      builder: (BuildContext context, AsyncSnapshot<List> snapshot) {
        if (snapshot.hasData) {
          var a = snapshot.data![0]["firstName"] as String;
          var b = snapshot.data![1]['Prediction'] as String;

Future <String> getData() async {
    var currentUser = FirebaseAuth.instance.currentUser;
   DocumentSnapshot q1 = await FirebaseFirestore.instance
        .collection('USER_TABLE')
        .doc(currentUser!.uid)
        .get();
    return q1.toString();
  }

  Future <String> getMood() async {
    var currentUser = FirebaseAuth.instance.currentUser;
    QuerySnapshot q2 = await FirebaseFirestore.instance
        .collection('userMood')
        .where('userId' == currentUser!.uid)
        .orderBy('createdAt',descending: true)
        .limit(1)
        .get();
    return q2.toString();
  }

                                                                   

Upvotes: 1

Views: 108

Answers (1)

Pavel
Pavel

Reputation: 5876

Let's simplify the task:

Future getA() async {
  await Future.delayed(Duration(seconds: 1));
  return 12.34;
}

Future getB() async {
  await Future.delayed(Duration(seconds: 1));
  return 'abc';
}

... FutureBuilder(
  future: Future.wait([getA(), getB()]),
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      // how to get a and b from snapshot?
    } else {
      return CircularProgressIndicator();
    }
  },
)

You're trying to do snapshot.data!['a'] and snapshot.data!['b']. It doesn't work because snapshot.data isn't Map<String, something>.

Future.wait returns Future<List<T>>. So snapshot.data will be List<T>, and you can get individual items like snapshot.data![0] and snapshot.data![1].

Another problem is that Future.wait doesn't support different item types, so the items type will be Object and you'll need to cast it manually.

Future<double> getA() async {
  await Future.delayed(Duration(seconds: 1));
  return 12.34;
}

Future<String> getB() async {
  await Future.delayed(Duration(seconds: 1));
  return 'abc';
}

... FutureBuilder<List<Object>>(
  future: Future.wait([getA(), getB()]),
  builder: (context, snapshot) {
    if (snapshot.hasData) {
      var a = snapshot.data![0] as double;
      var b = snapshot.data![1] as String;
      return Text('$a $b');
    } else {
      return CircularProgressIndicator();
    }
  },
)

Upvotes: 1

Related Questions