I have a listview where each item is one document from a firestore collection. I would like to tap the item and pass the document information to a details page.
This is how I am retrieving document information within the first stream:
child: Text(streamSnapshot.data.docs[index]['event_title'],
This is how I'm attempting to send the data to the next page:
child: GestureDetector(
onTap: () {
Navigator.pushNamed(context, EventPage.id, arguments: streamSnapshot.data.docs[index]);
},
I'm lost as to how to receive the passed data:
class _EventPageState extends State<EventPage> {
@override
final db = FirebaseFirestore.instance;
Widget build(BuildContext context) {
final args = ModalRoute.of(context)!.settings.arguments;
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(
middle: Text('event_title'),
),
child: Column(
I know I need a StreamBuilder on the next page, but do you have any insight on how to make that stream show only the passed in document?
I have worked out an answer to this question. I'm sure there are several ways to do this, but here's mine:
The key is to pass the firestore document ID to the next page. In this example code, I pass streamSnapshot.data.docs[index].id.toString()
as a parameter to a custom widget. I've located my named route within that widget.
StreamBuilder(
stream: FirebaseFirestore.instance
.collection('events')
.where('start_date', isGreaterThanOrEqualTo: DateTime.now())
.snapshots(),
builder: (context, AsyncSnapshot streamSnapshot) {
if (!streamSnapshot.hasData) {
return SizedBox(
height: 250,
child: Center(
child: CircularProgressIndicator(),
),
);
} else
return SizedBox(
height: 250,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: streamSnapshot.data.docs.length,
itemBuilder: (ctx, index) =>
EventListHorizontalTile(
//passes the document ID as a string down to the horizontally scrollable tile,
//where we push a named route with the docID string as an argument
firestoreDocID: streamSnapshot.data.docs[index].id.toString(),
image: streamSnapshot.data.docs[index]['main_image'],
name: streamSnapshot.data.docs[index]['name'],
),
),
);
}),
I then created a class to pass as an argument through a named route.
class Events {
final String firestoreDocID;
Events({
required this.firestoreDocID,
});
}
Now, within my EventListHorizontalTile
widget:
class EventListHorizontalTile extends StatelessWidget {
const EventListHorizontalTile({
Key? key,
required this.name,
this.firestoreDocID = '',
}) : super(key: key);
final String name;
final String firestoreDocID;
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
//Here I am pushing a named route with an argument, using that Events class I made earlier.
Navigator.pushNamed(context, EventPage.id, arguments: Events(firestoreDocID: firestoreDocID));
},
//child: The rest of the list tile widget
),
Now we have to write a bit of code in the EventPage
to receive the argument.
class EventPage extends StatefulWidget {
const EventPage({
Key? key,
}) : super(key: key);
static String id = 'EventPage';
@override
_EventPageState createState() => _EventPageState();
}
class _EventPageState extends State<EventPage> {
@override
Widget build(BuildContext context) {
//This is how we receive the argument.
final args = ModalRoute.of(context)!.settings.arguments as Events;
return CupertinoPageScaffold(
navigationBar: CupertinoNavigationBar(),
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
//Some text to see if the string made it.
Text(args.firestoreDocID),
]),
),
);
}
}
And that's it! Once you have that document ID in your new page, you can call a Streambuilder
like this:
StreamBuilder(
stream: FirebaseFirestore.instance
.collection('events')
.doc(args.firestoreDocID)
.snapshots(),