可以将用户数据写入Firebase,可以';不要从火场读到田野:颤栗
当用户试图编辑他们的信息时,我试图将我的用户数据读入表单字段。我可以向Firebase写入数据,但无法将用户数据读取和显示到内置字段中。为了区分,每个userData都以登录用户的mid作为userData的id进行存储 我错过了什么?下面是我的尝试 以下是我的UserData模型:可以将用户数据写入Firebase,可以';不要从火场读到田野:颤栗,firebase,flutter,google-cloud-firestore,flutter-change-notifier,change-notification,Firebase,Flutter,Google Cloud Firestore,Flutter Change Notifier,Change Notification,当用户试图编辑他们的信息时,我试图将我的用户数据读入表单字段。我可以向Firebase写入数据,但无法将用户数据读取和显示到内置字段中。为了区分,每个userData都以登录用户的mid作为userData的id进行存储 我错过了什么?下面是我的尝试 以下是我的UserData模型: class UserData { String id; String firstName; String lastName; String phoneNumber; String role;
class UserData {
String id;
String firstName;
String lastName;
String phoneNumber;
String role;
String businessName;
String businessType;
String streetAddress;
String city;
String state;
String postcode;
String country;
String businessTradingCurrency;
Timestamp createdAt;
Timestamp updatedAt;
UserData(
this.id,
this.firstName,
this.businessTradingCurrency,
this.businessType,
this.businessName,
this.city,
this.country,
this.createdAt,
this.lastName,
this.phoneNumber,
this.postcode,
this.role,
this.state,
this.streetAddress,
this.updatedAt,
);
UserData.fromMap(Map<String, dynamic> data) {
id = data['id'];
firstName = data['first_name'];
lastName = data['last_name'];
phoneNumber = data['phone_number'];
businessTradingCurrency = data['trading_currency'];
role = data['role'];
businessName = data['business_name'];
businessType = data['business_type'];
streetAddress = data['street_address'];
city = data['city'];
postcode = data['postcode'];
state = data['state'];
country = data['country'];
createdAt = data['created_at'];
updatedAt = data['updated_at'];
}
Map<String, dynamic> toMap() {
return {
'id': id,
'first_name': firstName,
'last_name': lastName,
'phone_number': phoneNumber,
'role': role,
'trading_currency': businessTradingCurrency,
'business_name': businessName,
'business_type': businessType,
'street_address': streetAddress,
'city': city,
'postcode': postcode,
'state': state,
'country': country,
'created_at': createdAt,
'updated_at': updatedAt,
};
}
}
类用户数据{
字符串id;
字符串名;
字符串lastName;
字符串电话号码;
字符串角色;
字符串businessName;
字符串业务类型;
字符串地址;
字符串城市;
字符串状态;
字符串邮政编码;
弦国;
贸易货币;
时间戳createdAt;
时间戳更新数据;
用户数据(
这个身份证,
这个名字,
这是商业交易货币,
这是一种商业模式,
这是商业名称,
这个城市,
这个国家,
这个.createdAt,
这个姓,
这个电话号码,
这是邮政编码,
这个角色,,
这个州,
这是我的地址,
这个.updatedAt,
);
UserData.fromMap(地图数据){
id=数据['id'];
firstName=数据['first_name'];
lastName=data['last_name'];
phoneNumber=数据[‘电话号码’];
businessTradingCurrency=数据[“交易货币];
角色=数据['role'];
businessName=数据['business_name'];
businessType=data['business_type'];
streetAddress=数据['street_address'];
城市=数据[‘城市’];
邮政编码=数据[‘邮政编码’];
状态=数据[‘状态’];
国家=数据[‘国家’];
createdAt=data['created_at'];
updatedAt=数据['updated_at'];
}
映射toMap(){
返回{
“id”:id,
“名字”:名字,
“姓氏”:姓氏,
“电话号码”:电话号码,
“角色”:角色,
“交易货币”:业务交易货币,
“业务名称”:业务名称,
“业务类型”:业务类型,
“街道地址”:街道地址,
“城市”:城市,
“邮政编码”:邮政编码,
“国家”:国家,
"国":国,,
“created_at”:createdAt,
'updated_at':updatedAt,
};
}
}
下面是我的UserData通知程序类:
class UserDataNotifier with ChangeNotifier {
UserData _currentLoggedInUserData;
CollectionReference userDataRef = Firestore.instance.collection('userData');
UserData get currentLoggedInUserData => _currentLoggedInUserData;
set currentLoggedInUserData(UserData userData) {
_currentLoggedInUserData = userData;
notifyListeners();
}
Future<void> getUserData() async {
String userId = (await FirebaseAuth.instance.currentUser()).uid.toString();
DocumentSnapshot result =
await Firestore.instance.collection('userData').document(userId).get();
_currentLoggedInUserData = result.data as UserData;
print('Phone Number: ${_currentLoggedInUserData.phoneNumber}');
notifyListeners();
}
Future createOrUpdateUserData(UserData userData, bool isUpdating) async {
String userId = (await FirebaseAuth.instance.currentUser()).uid;
if (isUpdating) {
userData.updatedAt = Timestamp.now();
await userDataRef.document(userId).updateData(userData.toMap());
print('updated userdata with id: ${userData.id}');
} else {
userData.createdAt = Timestamp.now();
DocumentReference documentReference = userDataRef.document(userId);
userData.id = documentReference.documentID;
await documentReference.setData(userData.toMap(), merge: true);
print('created userdata successfully with id: ${userData.id}');
}
notifyListeners();
}
}
将UserDataNotifier与ChangeNotifier一起分类{
UserData _currentLoggedInUserData;
CollectionReference userDataRef=Firestore.instance.collection('userData');
UserData获取currentLoggedInUserData=>\u currentLoggedInUserData;
设置currentLoggedInUserData(UserData UserData){
_currentLoggedInUserData=用户数据;
notifyListeners();
}
未来的getUserData()异步{
字符串userId=(等待FirebaseAuth.instance.currentUser()).uid.toString();
文档快照结果=
等待Firestore.instance.collection('userData').document(userId.get();
_currentLoggedInUserData=result.data作为UserData;
打印('电话号码:${u currentLoggedInUserData.phoneNumber}');
notifyListeners();
}
未来的createOrUpdateUserData(UserData UserData,bool IsUpdate)异步{
字符串userId=(等待FirebaseAuth.instance.currentUser()).uid;
如果(正在更新){
userData.updatedAt=Timestamp.now();
等待userDataRef.document(userId.updateData(userData.toMap());
打印('updated userdata with id:${userdata.id}');
}否则{
userData.createdAt=Timestamp.now();
DocumentReference DocumentReference=userDataRef.document(用户ID);
userData.id=documentReference.documentID;
等待documentReference.setData(userData.toMap(),merge:true);
打印('id:${userdata.id}已成功创建userdata');
}
notifyListeners();
}
}
这是我的编辑用户配置文件表单:
class ProfileFormScreen extends StatefulWidget {
static const String id = 'profile_form';
@override
_ProfileFormScreenState createState() => _ProfileFormScreenState();
}
class _ProfileFormScreenState extends State<ProfileFormScreen> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
UserData _currentLoggedInUserData;
bool showSpinner = false;
//global declarations
String selectedBusinessTypeDropDownValue = 'Fashion';
String selectedCurrencyDropDownValue = 'AUD: Australian Dollar';
String selectedCountryDropDownValue = 'Australia';
String email;
@override
void initState() {
super.initState();
UserDataNotifier userDataNotifier =
Provider.of<UserDataNotifier>(context, listen: false);
if (userDataNotifier.currentLoggedInUserData != null) {
_currentLoggedInUserData = userDataNotifier.currentLoggedInUserData;
} else {
_currentLoggedInUserData = UserData(
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
null,
);
}
}
@override
Widget build(BuildContext context) {
UserDataNotifier userDataNotifier =
Provider.of<UserDataNotifier>(context, listen: false);
print('Logged in user id: ${_currentLoggedInUserData.id}');
_saveUserData() async {
if (!_formKey.currentState.validate()) {
return;
}
_formKey.currentState.save();
userDataNotifier.createOrUpdateUserData(_currentLoggedInUserData, true);
Navigator.pop(context);
}
return Scaffold(
appBar: AppBar(
title: Text('Edit Profile'),
actions: <Widget>[
FlatButton(
onPressed: () => _saveUserData(),
child: Icon(
FontAwesomeIcons.save,
color: kThemeStyleButtonFillColour,
)),
],
),
body: ModalProgressHUD(
inAsyncCall: showSpinner,
child: SingleChildScrollView(
// padding: EdgeInsets.only(top: 20.0),
child: Form(
autovalidateMode: AutovalidateMode.always,
key: _formKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
LabelTextPadding(text: 'Business Information'),
//business name
RegularTextPadding(regText: 'Business Name'),
_buildBusinessName(),
SizedBox(height: 20.0),
//business type
RegularTextPadding(regText: 'Business Type'),
Platform.isIOS
? _buildCupertinoStyleBusinessType(context)
: _buildMaterialStyleBusinessType(context),
//Trading currency
RegularTextPadding(regText: 'Trading Currency'),
Platform.isIOS
? _buildCupertinoStyleTradingCurrency(context)
: _buildMaterialStyleTradingCurrency(context),
//business location
RegularTextPadding(regText: 'Location'),
//address 1
_buildAddress(),
//city
_buildCityField(),
//postcode
_buildPostcode(),
//state
_buildStateField(),
//country
Platform.isIOS
? _buildCupertinoStyleCountry(context)
: _buildMaterialStyleCountry(context),
SizedBox(
height: 20.0,
),
DividerClass(),
SizedBox(
height: 20.0,
),
//Personal information
LabelTextPadding(
text: 'Personal Information',
),
_buildFirstNameField(),
_buildLastNameField(),
_buildPhoneNumberField(),
// _buildEmailField(),
//cancel and save buttons
Padding(
padding: const EdgeInsets.fromLTRB(15.0, 10.0, 15.0, 10.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Buttons(
onPressedButton: () {
Navigator.pop(context);
},
buttonLabel: 'Cancel',
buttonColour: kThemeStyleButtonFillColour,
buttonTextStyle: kThemeStyleButton),
SizedBox(
width: 15.0,
),
Buttons(
onPressedButton: () => _saveUserData(),
buttonLabel: 'Save',
buttonColour: kThemeStyleButtonFillColour,
buttonTextStyle: kThemeStyleButton),
],
),
),
],
),
),
),
),
);
}
//business information
Widget _buildBusinessName() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.businessName,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.businessName = value;
},
validator: TextInputFieldValidator.validate,
decoration:
kTextFieldDecoration.copyWith(hintText: 'update business Name'),
),
);
}
//business type - cupertino and material styles
_buildCupertinoStyleBusinessType(BuildContext context) {
return GestureDetector(
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(5.0)),
border: Border.all(
color: kThemeStyleButtonFillColour,
width: 1,
)),
padding: const EdgeInsets.fromLTRB(10.0, 12.0, 10.0, 12.0),
margin: EdgeInsets.all(20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(selectedBusinessTypeDropDownValue),
Icon(
FontAwesomeIcons.caretDown,
color: kThemeStyleButtonFillColour,
),
],
),
),
onTap: () => showModalBottomSheet(
context: context,
builder: (BuildContext builder) {
return Container(
color: Colors.white,
height: MediaQuery.of(context).copyWith().size.height / 4,
child: CupertinoPicker(
magnification: 1.5,
children: List<Widget>.generate(businessType.length, (int index) {
return Center(
child: Text(
businessType[index].toString(),
softWrap: true,
style: TextStyle(fontSize: 15.0),
),
);
}),
itemExtent: 25,
onSelectedItemChanged: (index) {
setState(() {
selectedBusinessTypeDropDownValue = businessType[index];
});
},
),
);
},
),
);
}
_buildMaterialStyleBusinessType(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: kThemeStyleButtonFillColour,
width: 1,
)),
margin: EdgeInsets.all(20.0),
width: MediaQuery.of(context).size.width,
child: Center(
child: DropdownButton(
value: _currentLoggedInUserData.businessType == null
? selectedBusinessTypeDropDownValue
: _currentLoggedInUserData.businessType,
elevation: 15,
iconDisabledColor: kThemeStyleButtonFillColour,
iconEnabledColor: kThemeStyleButtonFillColour,
underline: Container(),
items: businessType
.map(
(businessType) => DropdownMenuItem(
value: businessType, child: Text(businessType)),
)
.toList(),
onChanged: (newValue) {
setState(() {
selectedBusinessTypeDropDownValue = newValue;
_currentLoggedInUserData.businessType = newValue;
});
},
),
),
);
}
//trading currency - cupertino and material styles
_buildCupertinoStyleTradingCurrency(BuildContext context) {
return GestureDetector(
onTap: () => showModalBottomSheet(
context: context,
builder: (BuildContext builder) {
return Container(
color: Colors.white,
height: MediaQuery.of(context).copyWith().size.height / 4,
child: CupertinoPicker(
magnification: 1.5,
children:
List<Widget>.generate(tradingCurrency.length, (int index) {
return Center(
child: Text(
tradingCurrency[index].toString(),
softWrap: true,
style: TextStyle(fontSize: 15.0),
),
);
}),
itemExtent: 25,
onSelectedItemChanged: (index) {
setState(() {
selectedCurrencyDropDownValue = tradingCurrency[index];
});
},
),
);
},
),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(0.5)),
border: Border.all(
color: kThemeStyleButtonFillColour,
width: 1,
)),
padding: const EdgeInsets.fromLTRB(10.0, 12.0, 10.0, 12.0),
margin: EdgeInsets.all(20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(selectedCurrencyDropDownValue),
Icon(
FontAwesomeIcons.caretDown,
color: kThemeStyleButtonFillColour,
),
],
),
),
);
}
_buildMaterialStyleTradingCurrency(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: kThemeStyleButtonFillColour,
width: 1,
)),
margin: EdgeInsets.all(20.0),
width: MediaQuery.of(context).size.width,
child: Center(
child: DropdownButton(
value: _currentLoggedInUserData.businessType == null
? selectedCurrencyDropDownValue
: _currentLoggedInUserData.businessTradingCurrency,
icon: Icon(
FontAwesomeIcons.caretDown,
color: kThemeStyleButtonFillColour,
),
elevation: 15,
underline: Container(
color: kThemeStyleButtonFillColour,
),
items: tradingCurrency
.map(
(tradingCurrency) => DropdownMenuItem(
value: tradingCurrency, child: Text(tradingCurrency)),
)
.toList(),
onChanged: (newValue) {
setState(() {
selectedCurrencyDropDownValue = newValue;
_currentLoggedInUserData.businessTradingCurrency = newValue;
});
},
),
),
);
}
//address field
_buildAddress() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.streetAddress,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.streetAddress = value;
},
validator: TextInputFieldValidator.validate,
decoration:
kTextFieldDecoration.copyWith(hintText: 'house and street address'),
),
);
}
//city field
_buildCityField() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.city,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.city = value;
},
validator: TextInputFieldValidator.validate,
decoration: kTextFieldDecoration.copyWith(hintText: 'enter city'),
),
);
}
//postcode field
_buildPostcode() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.postcode,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.postcode = value;
},
validator: TextInputFieldValidator.validate,
decoration: kTextFieldDecoration.copyWith(hintText: 'enter postcode'),
),
);
}
//state field
_buildStateField() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.state,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.state = value;
},
validator: TextInputFieldValidator.validate,
decoration: kTextFieldDecoration.copyWith(hintText: 'enter state'),
),
);
}
//country field - cupertino and material styles
_buildCupertinoStyleCountry(BuildContext context) {
return GestureDetector(
onTap: () => showModalBottomSheet(
context: context,
builder: (BuildContext builder) {
return Container(
color: Colors.white,
height: MediaQuery.of(context).copyWith().size.height / 4,
child: CupertinoPicker(
magnification: 1.5,
children: List<Widget>.generate(country.length, (int index) {
return Center(
child: Text(
country[index].toString(),
softWrap: true,
style: TextStyle(fontSize: 15.0),
),
);
}),
itemExtent: 25,
onSelectedItemChanged: (index) {
setState(() {
selectedCountryDropDownValue = country[index];
});
},
),
);
},
),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(0.5)),
border: Border.all(
color: kThemeStyleButtonFillColour,
width: 1,
),
),
padding: const EdgeInsets.fromLTRB(10.0, 12.0, 20.0, 12.0),
margin: EdgeInsets.all(20.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(selectedCountryDropDownValue),
Icon(
FontAwesomeIcons.caretDown,
color: kThemeStyleButtonFillColour,
),
],
),
),
);
}
_buildMaterialStyleCountry(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
border: Border.all(
color: kThemeStyleButtonFillColour,
width: 1,
),
),
margin: EdgeInsets.all(20.0),
width: MediaQuery.of(context).size.width,
child: Center(
child: DropdownButton(
value: _currentLoggedInUserData.country == null
? selectedCountryDropDownValue
: _currentLoggedInUserData.country,
elevation: 15,
iconDisabledColor: kThemeStyleButtonFillColour,
iconEnabledColor: kThemeStyleButtonFillColour,
underline: Container(),
items: country
.map(
(country) =>
DropdownMenuItem(value: country, child: Text(country)),
)
.toList(),
onChanged: (newValue) {
setState(() {
selectedCountryDropDownValue = newValue;
_currentLoggedInUserData.country = newValue;
});
},
),
),
);
}
//logged in user personal info build
//first name
_buildFirstNameField() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.firstName,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.firstName = value;
},
validator: TextInputFieldValidator.validate,
decoration: kTextFieldDecoration.copyWith(hintText: 'your first Name'),
),
);
}
//last name
_buildLastNameField() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.lastName,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.lastName = value;
},
validator: TextInputFieldValidator.validate,
decoration: kTextFieldDecoration.copyWith(hintText: 'your last name'),
),
);
}
//phone number
_buildPhoneNumberField() {
return Container(
padding: EdgeInsets.all(20.0),
child: TextFormField(
initialValue: _currentLoggedInUserData.phoneNumber,
textAlign: TextAlign.left,
onSaved: (value) {
_currentLoggedInUserData.phoneNumber = value;
},
validator: TextInputFieldValidator.validate,
decoration:
kTextFieldDecoration.copyWith(hintText: 'your phone number'),
),
);
}
}
class TextInputFieldValidator {
static String validate(String value) {
if (value.isEmpty) {
return 'This field can\'t be empty, you must enter a text';
}
if (value.length < 3) {
return 'You must enter at least a word';
}
return value;
}
}
class ProfileFormScreen扩展了StatefulWidget{
静态常量字符串id='profile_form';
@凌驾
_ProfileFormScreenState createState()=>\u ProfileFormScreenState();
}
类_ProfileFormScreenState扩展状态{
最终的GlobalKey _formKey=GlobalKey();
UserData _currentLoggedInUserData;
bool showSpinner=false;
//全球宣言
字符串selectedBusinessTypeDropDownValue='Fashion';
字符串selectedCurrencyDropDownValue='AUD:Australian Dollar';
字符串selectedCountryDropDownValue='Australia';
字符串电子邮件;
@凌驾
void initState(){
super.initState();
UserDataNotifier UserDataNotifier=
Provider.of(上下文,listen:false);
if(userDataNotifier.currentLoggedInUserData!=null){
_currentLoggedInUserData=userDataNotifier.currentLoggedInUserData;
}否则{
_currentLoggedInUserData=用户数据(
无效的
无效的
无效的
无效的
无效的
无效的
无效的
无效的
无效的
无效的
无效的
无效的
无效的
无效的
无效的
);
}
}
@凌驾
小部件构建(构建上下文){
UserDataNotifier UserDataNotifier=
Provider.of(上下文,listen:false);
打印('登录用户id:${u currentLoggedInUserData.id}');
_saveUserData()异步{
如果(!\u formKey.currentState.validate()){
返回;
}
_formKey.currentState.save();
createOrUpdateUserData(_currentLoggedInUserData,true);
Navigator.pop(上下文);
}
返回脚手架(
appBar:appBar(
标题:文本(“编辑配置文件”),
行动:[
扁平按钮(
onPressed:()=>\u saveUserData(),
子:图标(
FontAwesomeIcons.save,
颜色:KThemestyleButtonFillColor,
)),
],
),
正文:ModalProgressHUD(
inAsyncCall:showSpinner,
子:SingleChildScrollView(
//填充:仅限边缘设置(顶部:20.0),
孩子:表格(
autovalidateMode:autovalidateMode.always,
键:_formKey,
子:列(
mainAxisAlignment:mainAxisAlignment.spaceBetween,
crossAxisAlignment:crossAxisAlignment.start,
C