使用 Flutter 将表单上传到 Firestore
Posted
技术标签:
【中文标题】使用 Flutter 将表单上传到 Firestore【英文标题】:Upload Form to Firestore with Flutter 【发布时间】:2018-12-05 21:32:56 【问题描述】:我对如何在我的颤振应用中将表单上传到 Firestore 感到困惑。我已经阅读了许多教程,并且能够登录 Firebase 并将 Firestore 中的数据检索到我的颤振应用程序中,但我不知道如何将包含大量文本字段的表单上传到 Firestore。
示例:文档标题“书籍” 文本字段将包括:标题、作者等。
*** // 下面是我的页面,它确实从 Firestore 导入数据(这有效)。我添加了一个按钮,该按钮转到另一个页面,我试图在其中添加要上传到 Firestore 的表单(这不起作用)。页面加载有效,但未设置上传到 Firestore。
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
class FireStore extends StatelessWidget
FireStore(this.auth, this.onSignedOut);
final BaseAuth auth;
final VoidCallback onSignedOut;
void _signOut () async
try
await auth.signOut();
onSignedOut();
catch (e)
print (e);
@override
Widget build(BuildContext context)
return new Scaffold(
appBar: new AppBar(
title: new Text ('Welcome'),
actions: <Widget>[
new FlatButton(
child: new Text('Logout', style: new TextStyle(fontSize: 17.0, color: Colors.white)),
onPressed: _signOut
)
]
),
body: new StreamBuilder(
stream: Firestore.instance.collection('books').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot)
if (!snapshot.hasData) return CircularProgressIndicator();
return new GridView.count(
crossAxisCount: 2,
childAspectRatio: 1.0,
padding: const EdgeInsets.all(4.0),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
children: snapshot.data.documents.map((DocumentSnapshot document)
return new ListTile(
title: new Text(document['title']),
subtitle: new Text(document['author']),
);
).toList(),
);
,
),
floatingActionButton: new FloatingActionButton(
elevation: 0.0,
child: new Icon(Icons.add),
backgroundColor: new Color(0xFFE57373),
onPressed: ()
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new UploadFormField()),
);
)
);
// UPLOAD TO FIRESTORE
class UploadFormField extends StatefulWidget
@override
_UploadFormFieldState createState() => _UploadFormFieldState();
class _UploadFormFieldState extends State<UploadFormField>
GlobalKey<FormState> _key = GlobalKey();
bool _validate = false;
String title, author;
@override
Widget build(BuildContext context)
return MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text('Upload'),
),
body: new SingleChildScrollView(
child: new Container(
margin: new EdgeInsets.all(15.0),
child: new Form(
key: _key,
autovalidate: _validate,
child: FormUI(
)),
),
),
),
);
Widget FormUI()
return new Column(
children: <Widget>[
new TextFormField(
decoration: new InputDecoration(hintText: 'Title'),
validator: validateTitle,
onSaved: (String val)
title = val;
),
new TextFormField(
decoration: new InputDecoration(hintText: 'Author'),
validator: validateAuthor,
onSaved: (String val)
author = val;
),
new SizedBox(height: 15.0),
new RaisedButton(onPressed: _sendToServer, child: new Text('Upload'),
)
],
);
String validateTitle (String value)
String pattern = r' (^[a-zA-Z ]*$)';
RegExp regExp = new RegExp(pattern);
if (value.length == 0)
return 'Title is required';
else if (!regExp.hasMatch(value))
return "Title must be a-z and A-Z";
return null;
String validateAuthor (String value)
String pattern = r' (^[a-zA-Z ]*$)';
RegExp regExp = new RegExp(pattern);
if (value.length == 0)
return 'Author is required';
else if (!regExp.hasMatch(value))
return "Author must be a-z and A-Z";
return null;
_sendToServer()
if (_key.currentState.validate() )
//No error in validator
_key.currentState.save();
print ("Title $title");
print ("Author $author");
else
// validation error
setState(()
_validate = true;
);
【问题讨论】:
发布您开始使用的代码。 这是当前的代码/表单(我已经简化了)。如果您向下滚动大约一半,您将看到“UploadFormField”类。这就是我假设我需要上传 FIrestore 数据的地方。 【参考方案1】:我能够通过以下方式解决问题:
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'dart:async';
class FireStore extends StatelessWidget
FireStore(this.auth, this.onSignedOut);
final BaseAuth auth;
final VoidCallback onSignedOut;
void _signOut () async
try
await auth.signOut();
onSignedOut();
catch (e)
print (e);
@override
Widget build(BuildContext context)
return new Scaffold(
appBar: new AppBar(
title: new Text ('Welcome'),
actions: <Widget>[
new FlatButton(
child: new Text('Logout', style: new TextStyle(fontSize: 17.0, color: Colors.white)),
onPressed: _signOut
)
]
),
body: new StreamBuilder(
stream: Firestore.instance.collection('books').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot)
if (!snapshot.hasData) return CircularProgressIndicator();
return new GridView.count(
crossAxisCount: 2,
childAspectRatio: 1.0,
padding: const EdgeInsets.all(4.0),
mainAxisSpacing: 4.0,
crossAxisSpacing: 4.0,
children: snapshot.data.documents.map((DocumentSnapshot document)
return new ListTile(
title: new Text(document['title']),
subtitle: new Text(document['author']),
);
).toList(),
);
,
),
floatingActionButton: new FloatingActionButton(
elevation: 0.0,
child: new Icon(Icons.add),
backgroundColor: new Color(0xFFE57373),
onPressed: ()
Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new UploadFormField()),
);
)
);
// UPLOAD TO FIRESTORE
class UploadFormField extends StatefulWidget
@override
_UploadFormFieldState createState() => _UploadFormFieldState();
class _UploadFormFieldState extends State<UploadFormField>
GlobalKey<FormState> _key = GlobalKey();
bool _validate = false;
String title, author;
@override
Widget build(BuildContext context)
return MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text('Upload'),
),
body: new SingleChildScrollView(
child: new Container(
margin: new EdgeInsets.all(15.0),
child: new Form(
key: _key,
autovalidate: _validate,
child: FormUI(),
),
),
),
),
);
Widget FormUI()
return new Column(
children: <Widget>[
new TextFormField(
decoration: new InputDecoration(hintText: 'Title'),
validator: validateTitle,
onSaved: (String val)
title = val;
),
new TextFormField(
decoration: new InputDecoration(hintText: 'Author'),
validator: validateAuthor,
onSaved: (String val)
author = val;
),
new SizedBox(height: 15.0),
new RaisedButton(onPressed: _sendToServer, child: new Text('Upload'),
)
],
);
String validateTitle(String value)
String patttern = r'(^[a-zA-Z ]*$)';
RegExp regExp = new RegExp(patttern);
if (value.length == 0)
return "Title is Required";
else if (!regExp.hasMatch(value))
return "Title must be a-z and A-Z";
return null;
String validateAuthor(String value)
String patttern = r'(^[a-zA-Z ]*$)';
RegExp regExp = new RegExp(patttern);
if (value.length == 0)
return "Author is Required";
else if (!regExp.hasMatch(value))
return "Author must be a-z and A-Z";
return null;
_sendToServer()
if (_key.currentState.validate() )
//No error in validator
_key.currentState.save();
Firestore.instance.runTransaction((Transaction transaction) async
CollectionReference reference = Firestore.instance.collection('books');
await reference.add("Title": "$title", "Author": "$author");
);
else
// validation error
setState(()
_validate = true;
);
【讨论】:
【参考方案2】:Flutter 的 Firestore 插件将 Map 作为 setData 或 add 函数的输入,因此无论您在类对象或其他变量中拥有什么数据,您只需将其转换为 map(或嵌套数据结构的嵌套 map)并提供给setData 或添加函数作为输入以保存在 Firestore 中。对于类,颤振示例显示主要在类中实现了“toMap()”函数,该函数仅返回所需映射结构中的所有数据类对象,其对应的“fromMap(Map mapData)”将用于从稍后从 Firestore 获取数据时映射。
例如。
await Firestore.instance
.collection(TBL_USERS)
.add(
"type": "Dog",
"age": 6,
"breed": "abc",
);
或者由于它的map,你可以直接使用任何字符串(只要它在map中唯一)作为key
例如。
await Firestore.instance
.collection(TBL_USERS)
.add(
"Dog":
"age": 6,
"breed": "abc",
,
"Cat" :
"age": 2,
"breed": "xyz",
,
);
【讨论】:
我将把它放在我的代码中的什么位置?我的“上传”部分在“UploadFormField”类中。 另外,我使用了 Firestore 中的示例,文档名称为“books”,文本字段中包含“Title”和“Author”。以上是关于使用 Flutter 将表单上传到 Firestore的主要内容,如果未能解决你的问题,请参考以下文章
使用flutter将多张图片上传到firestore并获取它的下载URL并将所有URL保存到firebase
Flutter:添加动态 TextFormField 以将数据上传到列表