Issue
Above image is the screenshot of the firestore database which I want to read on the order screen. But unable to do so. I want to display the array orders
as a list of products on the order screen. Tried plenty of articles but unable to get the expected.
model_order.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class Order with ChangeNotifier {
final String userId;
final String orderId;
final String name;
int phoneNumber;
final String addressType;
final String address;
final String area;
final String city;
final String deliverySlot;
final Timestamp createdAt;
List<Map<String, dynamic>> orders;
Order({
required this.userId,
required this.orderId,
required this.name,
required this.phoneNumber,
required this.addressType,
required this.address,
required this.area,
required this.city,
required this.deliverySlot,
required this.createdAt,
required this.orders,
});
}
class OrderProvider with ChangeNotifier {
final List<Order> _orders = [];
List<Order> get getOrders => _orders;
Future<void> fetchOrders() async {
await FirebaseFirestore.instance
.collection('orders')
.orderBy('createdAt', descending: true)
.get()
.then((QuerySnapshot productSnapshot) {
for (var element in productSnapshot.docs) {
_orders.insert(
0,
Order(
userId: element.get('userId'),
orderId: element.get('orderId'),
name: element.get('name'),
phoneNumber: int.parse(element.get('phoneNumber').toString()),
addressType: element.get('addressType'),
address: element.get('address'),
area: element.get('area'),
city: element.get('city'),
deliverySlot: element.get('deliverySlot'),
createdAt: element.get('createdAt'),
orders: element.get(FieldPath(['orders', 'title'])),
),
);
}
});
}
// Order getById(String prodId) {
// // return _orders.firstWhere((element) => element.id == prodId);
// }
}
order_screen.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../models_providers/order.dart';
import 'package:intl/intl.dart';
class FullOrder extends StatefulWidget {
const FullOrder({
Key? key,
}) : super(key: key);
@override
_FullOrderState createState() => _FullOrderState();
}
class _FullOrderState extends State<FullOrder> {
@override
Widget build(BuildContext context) {
final order = Provider.of<Order>(context);
final orderProvider = Provider.of<OrderProvider>(context);
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Column(
children: [
Text('Order Id: ${order.orderId}'),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Order Date: ${DateFormat('dd/MM/yyyy').format(order.createdAt.toDate())}'),
Text(
'Order Time: ${DateFormat('kk:mm').format(order.createdAt.toDate())}'),
],
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Column(
children: [
const Text(
'Customer Name',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(order.name),
],
),
Column(
children: [
const Text(
'Contact',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text('${order.phoneNumber}'),
],
)
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Column(
children: [
const Text(
'Delivery Slot',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(order.deliverySlot),
],
),
Column(
children: [
const Text(
'Address',
style: TextStyle(fontWeight: FontWeight.bold),
),
Text('${order.addressType},${order.address}'),
Text(order.area),
Text(order.city),
],
),
ListView.builder(
itemCount: order.orders.length,
itemBuilder: (context, index) => Text(order.orders[index]['title']),
)
],
),
],
),
),
);
}
}
Solution
Pulling the orders out of an array field from a document should be no different than reading another value, with the exception that this is a List as opposed to a simpler structure or primitive value type. I created this Gist for you to see how it works (run it through Dartpad.dev and check it out), but basically is pretty much pulling the value out of the document and casting it as a List, then each value in turn you can map it as a Map<String, dynamic>, as shown below (shown inside a ListView.builder):
FutureBuilder(
// in my case I'm pulling all the documents in the "orders" collection
future: FirebaseFirestore.instance.collection('orders').get(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<QueryDocumentSnapshot> docs = (snapshot.data! as QuerySnapshot).docs;
return ListView.builder(
itemCount: docs.length,
itemBuilder: (context, index) {
// this is each individual document Map
var data = docs[index].data() as Map<String, dynamic>;
// now this is the "orders" array inside the document
var dataOrders = data['orders'] as List<dynamic>;
// then each individual object in the array is mapped in turn as another Map
var mappedDataOrders = dataOrders.map((o) => (o as Map<String, dynamic>)).toList();
// then do whatever you want with it
return Container(
padding: const EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(data['orderId'].toString(), style: TextStyle(fontSize: 30)),
const SizedBox(height: 20),
...List.generate(
mappedDataOrders.length,
(index) {
var order = mappedDataOrders[index] as Map<String, dynamic>;
return Text(order['title']);
}
)
]
)
);
}
)
Eventually you will have to map the orders array items the same way you are mapping the order documents (i noticed you have a List<Map<String, dynamic>> orders;) so you should map those into strongly-typed models (you could call them SubOrders or whatever you want).
This is how I replicated your Firebase on my end:
And this is how it looks when I run the Gist I gave you on DartPad:
Let me know if that works for you.
Answered By - Roman Jaquez
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.