I'm new to flutter and dart and trying to fetch data from firestore as a stream and feed to my ListView but I keep getting this error:
type 'MappedListIterable<DocumentSnapshot, Product>' is not a subtype
of type 'List<Product>'
I have seen a couple of other posts on stackoverflow like this but they either do not help me or do not apply to my situation.
This is my products page widget:
import 'package:xxx/models/Product.dart';
import 'package:agrogator/screens/products/widgets/products_list.dart';
import 'package:xxx/services/product.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ProductsScreen extends StatelessWidget {
ProductsScreen({Key key}) : super(key: key);
final product = ProductService();
// This widget is the productsucts page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
@override
@override
Widget build(BuildContext context) {
// This method is rerun every time setState is called, for instance as done
// by the _incrementCounter method above.
//
// The Flutter framework has been optimized to make rerunning build methods
// fast, so that you can just rebuild anything that needs updating rather
// than having to individually change instances of widgets.
return StreamProvider<List<Product>>.value(
value: product.streamProducts(),
child: new Scaffold(
appBar: new AppBar(
// Here we take the value from the MyHomePage object that was created by
// the App.build method, and use it to set our appbar title.
title: new Text("xxx"),
),
body: new ProductsList(),
floatingActionButton: new FloatingActionButton(
onPressed: () {},
tooltip: 'Increment',
child: new Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
),
);
}
}
This is my ProductsList widget:
import 'package:xxx/models/Product.dart';
import 'package:xxx/screens/products/widgets/product_item.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ProductsList extends StatelessWidget {
@override
Widget build(BuildContext context) {
var products = Provider.of<List<Product>>(context);
return Container(
height: 100,
child: ListView(
children: products.map((product) {
return new ProductItem(product: product);
}).toList(),
),
);
}
}
This is my ProductItem widget:
import 'package:xxx/models/Product.dart';
import 'package:flutter/material.dart';
class ProductItem extends StatelessWidget {
final Product product;
ProductItem({this.product});
@override
Widget build(BuildContext context) {
return Text(product.name, style: TextStyle(color: Colors.black));
}
}
This is my Product Model:
import 'package:cloud_firestore/cloud_firestore.dart';
class Product {
String uid;
String name;
String unit;
int avgQuantity;
double avgWeight;
double previousAvgPrice;
double currentAvgPrice;
String lastUpdatedBy;
String lastUpdatedAt;
String remarks;
Product(
{this.uid,
this.name,
this.unit,
this.avgQuantity,
this.avgWeight,
this.previousAvgPrice,
this.currentAvgPrice,
this.lastUpdatedBy,
this.lastUpdatedAt,
this.remarks});
factory Product.fromFirestore(DocumentSnapshot doc) {
Map data = doc.data;
return Product(
uid: doc.documentID,
name: data["name"],
unit: data["unit"],
avgQuantity: data["avgQuantity"],
avgWeight: data["avgWeight"],
previousAvgPrice: data["previousAvgPrice"],
currentAvgPrice: data["ccurrentAvgPrice"],
lastUpdatedBy: data["lastUpdatedBy"],
lastUpdatedAt: data["lastUpdatedAt"],
remarks: data["remarks"]);
}
}
And my service:
import 'package:xxx/models/Product.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class ProductService {
final Firestore _db = Firestore.instance;
Stream<List<Product>> streamProducts() {
var ref = _db.collection("products");
return ref
.snapshots()
.map((list) => list.documents.map((doc) => Product.fromFirestore(doc)));
}
}
In your Service add .toList()
Like this below
import 'package:xxx/models/Product.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class ProductService {
final Firestore _db = Firestore.instance;
Stream<List<Product>> streamProducts() {
var ref = _db.collection("products");
return ref
.snapshots()
.map((list) => list.documents.map((doc) => Product.fromFirestore(doc))).toList(); // <= here
}
}
You can try this. Hope this helps
Product Model
class Product {
String uid;
String name;
String unit;
int avgQuantity;
double avgWeight;
double previousAvgPrice;
double currentAvgPrice;
String lastUpdatedBy;
String lastUpdatedAt;
String remarks;
Product({this.uid,
this.name,
this.unit,
this.avgQuantity,
this.avgWeight,
this.previousAvgPrice,
this.currentAvgPrice,
this.lastUpdatedBy,
this.lastUpdatedAt,
this.remarks});
}
Product Service
class ProductService {
Stream<List<Product>> streamProducts() {
return _FirestoreStream<List<Product>>(
apiPath: "products",
parser: FirestoreProductsParser(),
).stream;
}
}
abstract class FirestoreNodeParser<T> {
T parse(QuerySnapshot querySnapshot);
}
class FirestoreProductsParser extends FirestoreNodeParser<List<Product>> {
List<Product> parse(QuerySnapshot querySnapshot) {
var products = querySnapshot.documents.map((documentSnapshot) {
return Product(
uid: doc.documentID,
name: data["name"],
unit: data["unit"],
avgQuantity: data["avgQuantity"],
avgWeight: data["avgWeight"],
previousAvgPrice: data["previousAvgPrice"],
currentAvgPrice: data["ccurrentAvgPrice"],
lastUpdatedBy: data["lastUpdatedBy"],
lastUpdatedAt: data["lastUpdatedAt"],
remarks: data["remarks"]
);
}).toList();
products.sort((lhs, rhs) => rhs.uid.compareTo(lhs.uid));
return products;
}
}
class _FirestoreStream<T> {
_FirestoreStream({String apiPath, FirestoreNodeParser<T> parser}) {
CollectionReference collectionReference = Firestore.instance.collection(apiPath);
Stream<QuerySnapshot> snapshots = collectionReference.snapshots();
stream = snapshots.map((snapshot) => parser.parse(snapshot));
}
Stream<T> stream;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With