I am trying to fetch data from firebase cloud store in my flutter project but getting this error. It works fine in displaying medicine pictures but as i click on the product it gives this error! Although it should display medicine_detail_page on click.
This is my code of one of my category "heartMedicine_page.dart"
import 'package:flutter/material.dart';
import 'medicine_detail_page.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
final List<Map<String, dynamic>> heartMedicines = [
{
'id': 0,
'name': 'A2A',
'price': 25,
'imgPath': 'assets/heart medicines/A2A.png',
'category': 'Heart',
'dosage': ['50/12.5mg'],
'description':
'The A2A receptor reduces glutamate uptake in astrocytes, through modulating the expression of glutamate transporters, GLT-1 and GLAST, and induces astrocytic proliferation and activation.'
},
{
'id': 1,
'name': 'Concor',
'price': 25,
'imgPath': 'assets/heart medicines/concor.png',
'category': 'Heart',
'dosage': ['2.5mg', '5.0mg', '10mg'],
'description':
'An antihypertensive medicine that works by slowing down the heart rate and relaxing blood vessels, ultimately reducing high blood pressure. Take this medicine in doses and duration as prescribed by the doctor. It can be taken with or without food.'
},
{
'id': 2,
'name': 'Olesta',
'price': 25,
'imgPath': 'assets/heart medicines/Olesta.png',
'category': 'Heart',
'dosage': ['2.5mg', '5.0mg', '10mg'],
'description':
'Olmesartan is used alone or together with other medicines to treat high blood pressure (hypertension). High blood pressure adds to the workload of the heart and arteries. If it continues for a long time, the heart and arteries may not function properly.'
},
{
'id': 3,
'name': 'Sacvin',
'price': 25,
'imgPath': 'assets/heart medicines/Sacvin.png',
'category': 'Heart',
'dosage': ['2.5mg', '5.0mg', '10mg'],
'description':
'SACVIN (Sacubitril/Valsartan) is indicated to reduce the risk of cardiovascular death and hospitalization for heart failure in patients with chronic heart failure (NYHA Class II-IV) and reduced ejection fraction.'
},
{
'id': 4,
'name': 'Ascard75',
'price': 25,
'imgPath': 'assets/heart medicines/Ascard75.png',
'category': 'Heart',
'dosage': ['2.5mg', '5.0mg', '10mg'],
'description':
'Ascard Tablet is an antiplatelet medicine (blood thinner). It contains aspirin as its active ingredient. It is used to prevent the formation of blood clots. This helps reduce the risk of heart attacks, stroke and angina due to blood clots.'
},
];
FirebaseFirestore db = FirebaseFirestore.instance;
class HeartMedicine extends StatefulWidget {
HeartMedicine({super.key});
@override
State<HeartMedicine> createState() => _HeartMedicineState();
}
class _HeartMedicineState extends State<HeartMedicine> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
'Heart Medicines',
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.red,
),
body: Container(
padding: EdgeInsets.all(8),
color: Colors.black12,
child: StreamBuilder(
stream: db.collection('heartMedicines').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData){
return Center(child: Text('PLease wait!'),);
}
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 4.0,
mainAxisSpacing: 4.0),
itemCount: snapshot.data!.docs.length,
itemBuilder: (BuildContext context, int index) {
DocumentSnapshot heartMedicines = snapshot.data!.docs[index];
return Card(
color: Colors.white,
elevation: 8,
child: GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => MedicineDetailPage(
heartMedicine: heartMedicines[index],
),
),
);
},
child: Container(
padding: EdgeInsets.all(8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Container(
height: 110,
child: Hero(
tag:
// 'medicine-image${heartMedicines[index]['id']}',
'medicine-image${heartMedicines['id']}',
child:
//Image.asset(heartMedicines[index]['imgPath'].toString(),
Image.asset(heartMedicines['imgPath'].toString(),
),
),
),
),
Text(
//heartMedicines[index]['name'].toString(),
heartMedicines['name'].toString(),
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 18),
),
Text(
// '\$${heartMedicines[index]['price'].toString()}',
'\$${heartMedicines['price'].toString()}',
style: TextStyle(fontSize: 18),
),
],
),
),
),
);
},
);
},
),
),
);
}
}
And this is my medicine_detail_page.dart:
import 'package:flutter/material.dart';
import 'package:login/cart_provider.dart';
import 'package:provider/provider.dart';
import 'heartMedicine_page.dart';
class MedicineDetailPage extends StatefulWidget {
final Map<String, dynamic> heartMedicine;
const MedicineDetailPage({required this.heartMedicine, super.key});
@override
State<MedicineDetailPage> createState() => _MedicineDetailPageState();
}
class _MedicineDetailPageState extends State<MedicineDetailPage> {
late String selectedDose;
@override
void initState() {
super.initState();
selectedDose = (widget.heartMedicine['dosage'] as List<String>)[0];
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.red,
title: Text(
'Medicine Detail',
style: TextStyle(color: Colors.white),
),
),
body: Container(
padding: EdgeInsets.all(16),
child: Column(
children: [
Text(
widget.heartMedicine['name'],
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
Spacer(),
Hero(
tag: 'medicine-image${widget.heartMedicine['id']}',
child: Image.asset(
widget.heartMedicine['imgPath'],width: 350,
height: 250,
),
),
SizedBox(
height: 20,
),
Container(
padding: EdgeInsets.all(8),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Colors.white),
child: Text(widget.heartMedicine['description'].toString()),
),
Spacer(),
Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Colors.white),
child: Column(
children: [
Text(
'\$${widget.heartMedicine['price'].toString()}',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
SizedBox(
height: 50,
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount:
(widget.heartMedicine['dosage'] as List<String>).length,
itemBuilder: (context, index) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 4),
child: InkWell(
onTap: () {
setState(() {
selectedDose = (widget.heartMedicine['dosage']
as List<String>)[index];
});
},
child: Chip(
backgroundColor: selectedDose ==
(widget.heartMedicine['dosage']
as List<String>)[index]
? Color.fromRGBO(245, 126, 130, 0.4)
: Color.fromRGBO(0, 0, 0, 0.1),
label: Text((widget.heartMedicine['dosage']
as List<String>)[index]
.toString())),
),
);
},
),
),
Container(
padding: EdgeInsets.all(16),
child: ElevatedButton.icon(
onPressed: () {
context.read<CartProvider>().addProduct({
'id': widget.heartMedicine['id'],
'name': widget.heartMedicine['name'],
'price': widget.heartMedicine['price'],
'imgPath': widget.heartMedicine['imgPath'],
'dosage': selectedDose
});
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('${widget.heartMedicine['name']} added to cart'),
),
);
},
icon: Icon(Icons.shopping_cart),
label: Text(
'Add to cart',
),
style: ElevatedButton.styleFrom(
backgroundColor: Colors.red.shade500,
foregroundColor: Colors.white,
minimumSize: Size(double.infinity, 50),
),
),
),
],
),
)
],
),
),
);
}
}
IDK about the rest, but note this line:
DocumentSnapshot heartMedicines = snapshot.data!.docs[index];
should be:
DocumentSnapshot heartMedicine = snapshot.data!.docs[index];
(already single snapshot, so using a plural name is confusing), and then pass it to the page like this:
MedicineDetailPage(
heartMedicine: heartMedicine.data() as Map<String, dynamic>,
)
EDIT: To explain the error you got:
Supported [field] types are [String] and [FieldPath]. Failed assertion: line 77 pos 7: 'field is String || field is FieldPath'
I have not tested it with your specific example, so I'm just guessing. Note that your original code has:
DocumentSnapshot heartMedicines = snapshot.data!.docs[index];
// then:
MedicineDetailPage(
heartMedicine: heartMedicines[index],
)
Since heartMedicines
is a DocumentSnapshot
, and you're calling heartMedicines[index]
with index
which is a number, it's complaining because that could be called with a String
or a FieldPath
, but not with a number
.
That is because getting properties from the snapshot without calling .data()
is possible like in this example:
FirebaseFirestore.instance
.collection('users')
.get()
.then((QuerySnapshot querySnapshot) {
querySnapshot.docs.forEach((doc) {
print(doc["first_name"]);
});
});