I'm trying to retrieve a firestore document in my app so that I can update it. Here's the current code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
void main() {
runApp(
MyApp(),
);
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Baby Names',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() {
return _MyHomePageState();
}
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Baby Name Votes')),
body: _buildBody(context),
);
}
Widget _buildBody(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('baby').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return LinearProgressIndicator();
return _buildList(context, snapshot.data.documents);
},
);
}
Widget _buildList(BuildContext context, List<DocumentSnapshot> snapshot) {
return ListView(
padding: const EdgeInsets.only(top: 20.0),
children: snapshot.map((data) => _buildListItem(context, data)).toList(),
);
}
Widget _buildListItem(BuildContext context, DocumentSnapshot data) {
final record = Record.fromSnapshot(data);
final docID = record.reference.documentID;
return Padding(
key: ValueKey(record.name),
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.circular(5.0),
),
child: ListTile(
title: Text(record.name),
trailing: Text(record.votes.toString()),
onTap: () {
print('Here is the record you have just clicked on: $docID, ${record.name}, ${record.votes}');
showModalBottomSheet(
context: context,
builder: (context) => EditVoteScreen(),
);
},
),
),
);
}
}
class EditVoteScreen extends StatefulWidget {
@override
_EditVoteScreenState createState() => _EditVoteScreenState();
}
class _EditVoteScreenState extends State<EditVoteScreen> {
String newBabyName = 'Gregg';
@override
Widget build(BuildContext context) {
return Container(
color: Color(0xff757575),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20.0), topRight: Radius.circular(20.0)),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Edit A Baby Name'),
SizedBox(height: 20.0),
Text(
'Current Name: ${record.name}',
),
SizedBox(height: 20.0),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Change Baby Name To:',
),
SizedBox(
width: 20.0,
),
DropdownButton<String>(
value: newBabyName,
icon: Icon(Icons.arrow_drop_down_circle),
iconSize: 24,
elevation: 16,
underline: Container(
height: 1,
color: Color(0xFF150A42),
),
onChanged: (String newValue) {
setState(() {
newBabyName = newValue;
});
},
items: <String>['Gregg', 'Mikey', 'Joey', 'Dave']
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
),
],
),
SizedBox(height: 20.0),
FlatButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0)),
color: Color(0xFF150A42),
textColor: Colors.white,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 12.0),
child: Text(
'💾 Save Changes',
),
),
onPressed: () {},
),
],
),
),
);
}
}
class Record {
final String name;
final int votes;
final DocumentReference reference;
Record.fromMap(Map<String, dynamic> map, {this.reference})
: assert(map['name'] != null),
assert(map['votes'] != null),
name = map['name'],
votes = map['votes'];
Record.fromSnapshot(DocumentSnapshot snapshot)
: this.fromMap(snapshot.data, reference: snapshot.reference);
@override
String toString() => "Record<$name:$votes>";
}
The firestore database only has two fields. Here's some sample data: name: 'James' (String), and votes: 2 (number)
When you click on a record in the app, I've managed to get it to print out the docID in the console, as well as the name and votes. The question is, how can i then take the document that I have just clicked on and display it in the ModalBottomSheet so that the name field can be updated?
If I can get it to display in the name field in the ModalBottomSheet, I should be able to figure out how to update it by myself. But I'm struggling to even get it to show up in there! My current code displays the error undefined name 'record'.
Any help would be greatly appreciated!
Thank you
Jason
You need to add a constructor to your EditVoteScreen widget and pass in the document's information so you can use it in your EditVoteScreen's build method:
class EditVoteScreen extends StatefulWidget {
final Record record;
const EditVoteScreen({Key key, this.record}) : super(key: key);
@override
_EditVoteScreenState createState() => _EditVoteScreenState();
}
Pass in the record when you create the class:
showModalBottomSheet(
context: context,
builder: (context) => EditVoteScreen(record: record,),
);
Then reference it within the state class by refering to the widget variable.
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Edit A Baby Name'),
SizedBox(height: 20.0),
Text(
'Current Name: ${widget.record.name}', // Here
),