dart_meteor icon indicating copy to clipboard operation
dart_meteor copied to clipboard

listen collection

Open ariadys opened this issue 4 years ago • 10 comments

can i convert result of Map<String, dynamic> from listen collection into List?

ariadys avatar Aug 20 '21 22:08 ariadys

The meteor.collection('') returns Stream<Map<String, dynamic>> which you can then able to use with the Flutter's StreamBuilder.

If you print it out you will see the format of returning object is: { 'id1': Map<String, dynamic>, 'id2': Map<String, dynamic>, ... }

To get the list from that you can do:

meteor.collection('messages').listen((result) {
  var listOfMessages = result.values.toList();
}

or with the StreamBuilder

StreamBuilder<Map<String, dynamic>>(
  stream: meteor.collection('messages'),
  builder: (BuildContext context, AsyncSnapshot<Map<String, dynamic>> snapshot) {
    if (snapshot.hasData) {
      var listOfMessages = snapshot.data.values.toList();
      ...
      ...

tanutapi avatar Aug 21 '21 02:08 tanutapi

Thanks @tanutapi , but I have a problem.. i've listen to the collection in initState but if the app is opened it has a few seconds delay to receive data. how can i add loading before receive data?

ariadys avatar Aug 21 '21 04:08 ariadys

void initState() {
    super.initState();
      meteor.collection('locations').listen((data) {
          storeList = data.values.toList();
          isLoading = false;
      });
 }

isLoading still true..

ariadys avatar Aug 21 '21 05:08 ariadys

You could share your full widget code if it is possible.

tanutapi avatar Aug 21 '21 14:08 tanutapi

Sure,

class ProductPotrait extends StatefulWidget {
  ProductPotrait({Key? key}) : super(key: key);

  @override
  _ProductPotraitState createState() => _ProductPotraitState();
}

class _ProductPotraitState extends State<ProductPotrait> {
  late SubscriptionHandler _subscriptionHandler;
  bool isLoading = true;
  late List storeList;

  @override
  void initState() {
    super.initState();
   _subscriptionHandler = meteor.subscribe('stores.all');
    meteor.collection('locations').listen((data) {
        storeList = data.values.toList();
        isLoading = false;
    });
 }

  @override
  void dispose() {
    super.dispose();
    _subscriptionHandler.stop();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      child: isLoading
          ? Loading()
          : Container(),
    );
  }
}

ariadys avatar Aug 21 '21 14:08 ariadys

  1. Do you forget to use setState() in your listening function? You should do:
meteor.collection('locations').listen((data) {
  setState(() {
    storeList = data.values.toList();
    isLoading = false;
  });
});
  1. I would suggest you use the StreamBuilder when you build your widget rather than do it in the initState.
Widget build(BuildContext context) {
  return StreamBuilder(
    stream: meteor.collection('locations'),
    builder: (context, AsyncSnapshot<Map<String, dynamic>> snapshot) {
      if (snapshot.hasData) {
        var storeList = snapshot.data.values.toList();
        return YourAnyStoreListWidget(storeList);
      }
      return Loading();
    },
  );
}

tanutapi avatar Aug 21 '21 14:08 tanutapi

ah, maybe I like solution number 2, coz number 1 will triggered memory leak

ariadys avatar Aug 21 '21 15:08 ariadys

how about 2 collection listen? @tanutapi

meteor.collection('category').listen((data) {
  setState(() {
    category = data.values.toList();
  });
});

meteor.collection('locations').listen((data) {
 if(category.length > 0){
  setState(() {
    storeList = data.values.toList();
  });
 }
});

ariadys avatar Aug 30 '21 02:08 ariadys

On solution number 1, you must stop listening on your widget dispose().

tanutapi avatar Jun 27 '22 15:06 tanutapi

Cloud you try Rx.combineLatest2 as described in https://stackoverflow.com/questions/55285903/dartlang-rxdart-merge-different-type-streams?

Something like

import 'package:rxdart/rxdart.dart';

...
...

_sub = Rx.combineLatest2(
   meteor.collection('category'), meteor.collection('locations'), (category, locations) {
  return [category, locations];
}).listen((combine) {
  setState(() {
     final category = (combine[0] as Map<String, dynamic>).values.toList();
    final locations = (combine[1] as Map<String, dynamic>).values.toList();
  });
});

...
...
_sub.cancel();

tanutapi avatar Jun 27 '22 15:06 tanutapi