Writing to Firebase Realtime Database with Flutter - firebase

I've perused the forums, google, and youtube for info on writing data to a real-time database with flutter and haven't found a proper guide for even the most basic write.
That being said, in my app, I am currently trying to save the user's email to the database as a child of the user's new id. I am attempting to do this immediately after calling .createUserWithEmailAndPassword. This all should occur on click of a Material Button. I previously had the write inside of the then statement, but that was giving me an error.
Code:
FirebaseAuth userAuth = FirebaseAuth.instance;
void saveEmailInDb(String userId, String email) {
final userRef = FirebaseDatabase.instance.reference();
userRef.child(userId).child("Email").push().set(email);
}
//inside of the build widget
MaterialButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32),
),
color: colorPalette.chooseColor('yellow'),
child: Container(
padding: EdgeInsets.all(13),
child: Text(
'Register',
style: GoogleFonts.ubuntu(
color: colorPalette.chooseColor('darkGrey'),
fontSize: 17),
),
),
onPressed: () async {
try {
UserCredential userCredential = await userAuth
.createUserWithEmailAndPassword(
email: tecEmail.text,
password: tecPassword.text)
.then(
(value) => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LoadingPage(),
),
),
);
saveEmailInDb(
userCredential.user.uid, tecEmail.text);
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
print('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
print('The account already exists for that email.');
}
} catch (e) {
print(e);
}
},
),
I have instantiated firebase in the main widget:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
GetMaterialApp(
home: LoadingPage(),
),
);
}
Now, I know that flutter is hooked up properly to my app because an account is created in the firebase console under authentication. However, nothing is written to the database and as there are no proper guides or official documentation, I am unsure how to proceed.
Database Rules:
{
"rules": {
".read": true,
".write": true
}
}

Answer: Moving the navigation code outside of the then statement, and below the database write, was sufficient to solve this problem. Basically, the navigation was poping the widget before the database code was called. Revised code below:
MaterialButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(32),
),
color: colorPalette.chooseColor('yellow'),
child: Container(
padding: EdgeInsets.all(13),
child: Text(
'Register',
style: GoogleFonts.ubuntu(
color: colorPalette.chooseColor('darkGrey'),
fontSize: 17),
),
),
onPressed: () async {
try {
UserCredential userCredential =
await userAuth.createUserWithEmailAndPassword(
email: tecEmail.text,
password: tecPassword.text);
saveEmailInDb(userCredential.user.uid, tecEmail.text);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LoadingPage(),
),
);
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
print('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
print('The account already exists for that email.');
}
} catch (e) {
print(e);
}
},
),

Related

i have a code made for firebase realtime database and i want to write same code for cloud firestore

i succesfully added user's phone number when user register with phone auth firebase now i want to fetch that user from firestore when i press login button and login with that user
Container(
margin: EdgeInsets.all(10),
width: double.infinity,
child: MaterialButton(
color: Colors.blue,
onPressed: () {
dbRef.reference().orderByChild("mobile").
equalTo(_controller.text).get().then((value) {
if(value.value==null)
{
_scaffoldkey.currentState!
.showSnackBar(SnackBar(content: Text('No User Found')));
return;
}
print("User Password ${value.value}");
Map data= value.value;
data.forEach((key, value) {
if(_passwordcontroller.text==value['password']&&(_controller.text==value['mobile']))
{
print("User Exist");
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => Home(key,value['name'])),
(route) => false);
}else
{
print("User Not found Exist");
}
});
});
},
child: Text(
'Login',
style: TextStyle(color: Colors.white),
),
),
),

How to fetch current user(Logged In user) details from particular collection in firebase?

Registration.dart
In this code we have tried to register a user i.e. doctor details in the collection named 'doctor' and after registering it is navigating to login page(Login_Screen.dart). We are able to fetch and display current user name and email id ({user?.displayName},{user?.email}),but we are struggling to fetch other details of that user from collection 'doctor'.
child: RaisedButton(
textColor: Color(0xFF003058),
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
color: Colors.orange[700],
child: Text('Register',
style: TextStyle(
fontSize: 22.0, fontWeight: FontWeight.w900)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0)),
onPressed: () async {
if (!_formKey.currentState!.validate()) {
return;
} else {
await Doctors.add({
"name": _name,
"email": _email,
"license": _license,
"password": _password,
"cpassword": _cpassword,
"role":role
}).then((value) => print("Doctors details Added"));
try {
UserCredential user =
await auth.createUserWithEmailAndPassword(
email: _email, password: _password);
if (user != null) {
await auth.currentUser!
.updateProfile(displayName: _name);
}
} catch (e) {
print(e);
}
}
Navigator.push(
context,
MaterialPageRoute(builder: (context) => LoginPage()),
);
_formKey.currentState!.save();
},
),
Login_Screen.dart
child: RaisedButton(
textColor: Color(0xFF003058),
padding: EdgeInsets.fromLTRB(10, 0, 10, 0),
color: Colors.orange[700],
child: Text('Sign in',
style: TextStyle(
fontSize: 22.0, fontWeight: FontWeight.w900)),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0)),
onPressed: () async {
if (!_formKey.currentState!.validate()) {
return;
} else {
try {
final user = (await FirebaseAuth.instance
.signInWithEmailAndPassword(
email: emailController.text,
password: passwordController.text,
))
.user;
if (user != null) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => App()),
);
}
} catch (e) {
print(e);
}
}
_formKey.currentState!.save();
print(emailController.text);
print( passwordController.text);
},
),
This would depend on how you are storing the current user data in the collection,
if you are storing the current users data in a collection with location "Users/userID" where userID is the user's id , you can reach the user's data like:
await users.doc("Users/${FirebaseAuth.instance.currentUser!.uid}").get();
and in case you mean reaching the current logged in data in general, not the data that you store in a collection, you can do so simpley by calling:
FirebaseAuth.instance.currentUser!.uid : to get the current user id (as we did above)
FirebaseAuth.instance.currentUser!.phoneNumber: to get the current user's phone number.
FirebaseAuth.instance.currentUser!.displayName: to get the current user's display name.
and there are other kinds of data you can get.

How to find Firebase document field and delete document

I have a button that lets a user delete their account. When users signup their email and name is saved to a Firestore collection called users, I want to search in the collection's documents where the uid field is equal to the current user uid then delete that document. Deleting the account works but not the document and I'm not getting any errors, I'm not sure what I'm doing wrong...
CollectionReference users = FirebaseFirestore.instance.collection('users');
TextButton(
onPressed: () async {
try {
await users
.where('uid', isEqualTo: _auth.currentUser!.uid).firestore.doc(users.doc().path).delete();
await _auth.currentUser!.delete().then((value) =>
Navigator.pushReplacement(context, MaterialPageRoute(
builder: (context) => const WelcomeScreen())));
} on FirebaseAuthException catch (error) {
Fluttertoast.showToast( msg: error.message.toString(),
gravity: ToastGravity.TOP,
backgroundColor: Colors.red,
textColor: Colors.white);
} on FirebaseException catch (error) { Fluttertoast.showToast(
msg: error.message.toString(),
gravity: ToastGravity.TOP,
backgroundColor: Colors.red,
textColor: Colors.white);
}
},
child: const Text( 'Delete', style: TextStyle(color: Colors.red),
))
I got the problem I was just working on my app and found a similar code so here is the solution. Just declare user id as variable for ease not necessary (optional) like this
final uid = _auth.currentUser!.uid; //optional
& then use this in your code:-
await users.doc(uid).delete();
instead of
await users
.where('uid', isEqualTo: _auth.currentUser!.uid).firestore.doc(users.doc().path).delete();
and Boom now it works like an charm!!
Hope this works!!

"Unexpected null value" error when trying to write data to cloud firestore

I am working on a sign up page for a web app. The code below shows how I am trying to authenticate users as well as add their data to cloud firestore. However I am getting an error saying that something is null even though I make sure to fill out the sign up info correctly.
I am assuming that the error comes from the try/catch block towards the bottom. I have followed the docs on flutterfire website to add user data to the cloud firestore database
(https://firebase.flutter.dev/docs/firestore/usage).
Also, what would be the best way to implement the addUser() function to avoid errors?
here is my code:
class SignUpPage extends StatefulWidget {
#override
_SignUpPageState createState() => _SignUpPageState();
}
class _SignUpPageState extends State<SignUpPage> {
FirebaseAuth auth = FirebaseAuth.instance;
final emailController = TextEditingController();
final passwordController = TextEditingController();
final nameController = TextEditingController();
User? firebaseUser = FirebaseAuth.instance.currentUser;
#override
Widget build(BuildContext context) {
CollectionReference firestoreData =
FirebaseFirestore.instance.collection('users');
Future<void> addUser() {
return firestoreData
.add({
'email': emailController.text,
'name': nameController.text,
'login_UID': firebaseUser!.uid,
'isCounselor': false,
})
.then((value) => print("User Added"))
.catchError((error) => print("Failed to add user: $error"));
}
return Scaffold(
body: Container(
padding: EdgeInsets.all(300),
child: Column(
children: [
TextField(
controller: nameController,
decoration: InputDecoration(labelText: 'Prénom'),
),
TextField(
controller: emailController,
decoration: InputDecoration(labelText: 'Email'),
),
TextField(
controller: passwordController,
decoration: InputDecoration(labelText: 'Mot de Passe'),
),
SizedBox(
height: 30,
),
MaterialButton(
child: Text('Sign up'),
onPressed: () async {
try {
UserCredential userCredential = await FirebaseAuth.instance
.createUserWithEmailAndPassword(
email: emailController.text,
password: passwordController.text);
addUser();
} on FirebaseAuthException catch (e) {
if (e.code == 'weak-password') {
print('The password provided is too weak.');
} else if (e.code == 'email-already-in-use') {
print('The account already exists for that email.');
}
} catch (e) {
print(e);
}
Navigator.pushNamed(context, '/login');
},
),
],
)),
);
}
}

How to call a function ASA the app runs in flutter?

I have an application that do login with the help of firestore database and I want to do autologin so I made a boolean and set it to false in the database and made the login function set it to true as he or she sign in, so I want to check if the person have already signed in or not as the app runs, any ideas :) ?
here my code:
void getUserData() async {
try {
var firebaseUser = await FirebaseAuth.instance.currentUser();
firestoreInstance
.collection("Students")
.document(usernameController.text)
.get()
.then((value) {
setState(() {
email = (value.data)['email'];
password = (value.data)['password'];
gender = (value.data)['gender'];
loggedin = (value.data)['token'];
});
});
} catch (e) {
print(e.toString);
}
}
You dont have to use a boolean to check if the user is logged in or not. Firebase authentication already offers that. You can check inside the initState:
#override
void initState() {
super.initState();
FirebaseAuth.instance.currentUser().then((res) {
print(res);
if (res != null) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => Home(uid: res.uid)),
);
}
else
{
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SignUp()),
);
}
});
}
Checks if there is a current user or not and navigates to the required page.
If you have different types of users, then you have to identify them in the database. So authenticate in firebase authentication, and use a userType field in the database:
void registerToFb() {
firebaseAuth
.createUserWithEmailAndPassword(
email: emailController.text, password: passwordController.text)
.then((result) {
firestoreInstance.collection("users").document(result.user.uid).setData({
"email": emailController.text,
"name": nameController.text,
"userType" : "Students"
}).then((res) {
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => Home(uid: result.user.uid)),
);
});
}).catchError((err) {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text("Error"),
content: Text(err.message),
actions: [
FlatButton(
child: Text("Ok"),
onPressed: () {
Navigator.of(context).pop();
},
)
],
);
});
});
}

Resources