如何使用 flutter 检索 firestore 中的特定文档

How to retrieve a specific document in firestore with flutter

我正在尝试在我的应用程序中检索一个 firestore 文档,以便我可以更新它。这是当前代码:

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>";
}

firestore 数据库只有两个字段。下面是一些示例数据:name: 'James' (String), and votes: 2 (number)

当您在应用程序中单击一条记录时,我设法让它在控制台中打印出 docID,以及名称和投票。问题是,我怎样才能将我刚刚单击的文档显示在 ModalBottomSheet 中,以便更新名称字段?

如果我能让它显示在 ModalBottomSheet 的名称字段中,我应该能够自己弄清楚如何更新它。但我什至都在努力让它出现在那里!我当前的代码显示错误 undefined name 'record'.

如有任何帮助,我们将不胜感激!

谢谢

贾森

您需要向 EditVoteScreen 小部件添加一个构造函数并传入文档的信息,以便您可以在 EditVoteScreen 的构建方法中使用它:

class EditVoteScreen extends StatefulWidget {
  final Record record;
  const EditVoteScreen({Key key, this.record}) : super(key: key); 
  @override
  _EditVoteScreenState createState() => _EditVoteScreenState();
}

创建时传入记录 class:

showModalBottomSheet(
    context: context,
    builder: (context) => EditVoteScreen(record: record,),
);

然后在状态class中通过引用widget变量来引用它。

child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Edit A Baby Name'),
            SizedBox(height: 20.0),
            Text(
              'Current Name: ${widget.record.name}', // Here
            ),