4

So im trying to stream data from firestore but when printing the data I get:

I/flutter ( 8356): Closure: () => Map<String, dynamic> from Function 'data':.

I am using this code to fetch the data:

 void messagesStream() async {
    Stream collectionStream = _firestore.collection('messages').snapshots();
    await for (var snapshot in collectionStream) {
      for (var message in snapshot.docs) {
        print(message.data());
      }
    }

When new data is added to the messages collection I get the Closure message so it is interacting with the databse.

What I want is it to print out the contents of the new document within the collection.

Any help is appreciated.

Daniel Booth
  • 73
  • 2
  • 6
  • You'll get the data as map. You can get the value by getting the value from map, or convert the data to a local object from a class you created. – Farhan Syah Sep 29 '20 at 15:08

4 Answers4

3

That's not the way you're supposed to iterate the results of a Stream. If you have a Stream and you want to process its results, you're supposed to use listen() to receive the results asynchronously.

Stream collectionStream = _firestore.collection('messages').snapshots();
collectionStream.listen((QuerySnapshot querySnapshot) {
    querySnapshot.documents.forEach((document) => print(document.data()));
}

See also: Firestore collection query as stream in flutter

You might also want to review the documentation to learn how to query Firestore in Flutter.

Doug Stevenson
  • 297,357
  • 32
  • 422
  • 441
3
void getMessages() async {
   final messages= await _firestore.collection('messages').get();
   for(var message in messages.docs){
     print(message.data());

   }

this is working check this and call getMessages() wherever you wana call

1

I encountered the same issue with pretty much your exact same code (sans your Stream variable). My suggestion is to delete the Stream var altogether (I tested the code below and got it to print the data from the Firestore database) :

    void messagesStream() async {
    await for (var snapshot in _firestore.collection('messages').snapshots()) {
      for (var message in snapshot.docs) {
        print(message.data());
      }
    }
  }

Alternatively, try addding QuerySnapShot as the data type for your Stream variable (untested):

Stream<QuerySnapshot> collectionStream = _firestore.collection('messages').snapshots();

You could also replace the entire method by creating a new Stateless Widget (MessagesStream) that returns a StreamBuilder:

class MessagesStream extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StreamBuilder<QuerySnapshot>(
      stream: _firestore.collection('messages').snapshots(),
      builder: (context, snapshot) {
       final messages = snapshot.data.docs;
       for (var message in messages) {
       print(message.data());
 }

...and call it wherever you see fit while you test:

class _ChatScreenState extends State<ChatScreen> { (...)
body: Column(children: <Widget> [
//Just an example.
MessageStream(),
   ],
  ),
(...)
}

***Be sure you make the _fireStore (which should be a FirebaseFirestore.instance) a global variable if you're going with the Stateless Widget route.

  • I think this question relates to a beginner Flutter class and the instructor will end-up with proper code. I'm in that class and it's exactly the same as my class. – Mark Gavagan Nov 03 '20 at 23:10
0

I received this error while trying to throw a custom error class InkError:

  • You meed add toMap the class.

final response = await http.post(url, body: body, headers: headers);
    final json = jsonDecode(response.body);
    if (response.statusCode == HttpStatus.ok) {
      return json;
    } else {
      throw InkError(
        code: 0,
        message: json['message'],
        statusCode: response.statusCode,
      ).toMap();

InkError

 class InkError {
  /// Error code.
  final int code;

  /// Error message.
  final String message;

  /// HTTP Status Code
  final int? statusCode;

  const InkError({
    required this.code,
    required this.message,
    this.statusCode,
  });

  factory InkError.fromJSON(Map<String, dynamic> json) => InkError(
        code: json['code'] as int,
        message: json['message'] as String,
        statusCode: json['statusCode'],
      );

  Map<String, dynamic> toMap() {
    return {
      'code': code,
      'message': message,
      'statusCode': statusCode,
    };
  }

  @override
  String toString() {
    return toMap().toString();
  }
}
ahmnouira
  • 1,607
  • 13
  • 8