how to add map data to cloud firestore in flutter? - flutter

I want to add the name of the user as a map containing 'firstName' and 'lastName'. I already have the user model and the name model, here is the code:
name_model.dart
class Name {
final String firstName;
final String lastName;
Name({
required this.firstName,
required this.lastName,
});
Map<String, dynamic> toMap() {
return {
'firstName': firstName,
'lastName': lastName,
};
}
Name.fromMap(Map<String, dynamic> nameMap)
: firstName = nameMap['firstName'],
lastName = nameMap['lastName'];
}
user_model.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:ukk_backup/models/name_model.dart';
class User {
final String? docId;
final String email;
final String password;
final String phoneNumber;
final Name name;
User({
this.docId,
required this.email,
required this.password,
required this.phoneNumber,
required this.name,
});
Map<String, dynamic> toMap() => {
'docId': docId,
'email': email,
'password': password,
'phoneNumber': phoneNumber,
'name': name.toMap(),
};
User.fromDocumentSnapshot(DocumentSnapshot<Map<String, dynamic>> doc)
: docId = doc.id,
email = doc['email'],
password = doc['password'],
phoneNumber = doc['phoneNumber'],
name = Name.fromMap(doc['name']);
}
when I pressed the register button I want all the data to be saved in cloud firestore, including the name with the map type. This is the onPressed:
onPressed: (() async {
if (_formKey.currentState!.validate()) {
DatabaseService service = DatabaseService();
User user = User(
email: emailController.text,
password: passwordController.text,
phoneNumber: phoneNumberController.text,
name: , //what to type?
);
setState(() {
_isLoading = true;
});
await service.addUser(user);
setState(() {
_isLoading = false;
});
}
}),
If you found some of my code is not correct or you found the solution, please tell me. Thank you.
Edit:
database_services.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:ukk_backup/models/user_model.dart';
class DatabaseService {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
addUser(User userData) async {
await _firestore.collection('users').add(userData.toMap());
}
updateUser(User userData) async {
await _firestore
.collection('users')
.doc(userData.docId)
.update(userData.toMap());
}
Future<void> deleteUser(String documentId) async {
await _firestore.collection('users').doc(documentId).delete();
}
Future<List<User>> retrieveUser() async {
QuerySnapshot<Map<String, dynamic>> snapshot =
await _firestore.collection('users').get();
return snapshot.docs
.map((docSnapshot) => User.fromDocumentSnapshot(docSnapshot))
.toList();
}
}

I misunderstood your question first. Your DataBaseService class looks ok to me. So if I am right the only problem you have is that you do not know how to add the name to the UserObject. If that's the essence of your question then that is very easy:
onPressed: (() async {
if (_formKey.currentState!.validate()) {
DatabaseService service = DatabaseService();
User user = User(
email: emailController.text,
password: passwordController.text,
phoneNumber: phoneNumberController.text,
name: Name(firstName: firstNameController.text, lastName: lastNameController.text),
);
setState(() {
_isLoading = true;
});
await service.addUser(user);
setState(() {
_isLoading = false;
});
}
}),

Related

flutter - how to pass required parameters when they have not yet been initialized

I am creating a userModel instance inside my authController and want to add obs from Getx to that userModel like: Rx<model.User>? userModel = model.User().obs;, but the fields inside my model.User are all required.
How can I pass these parameters if they have not yet been initialized as they will get initialized after the user signs in?
I referred this github: Github where he has done it because his parameters are not "required" as it is old, but now flutter is null safe and is forcing "required" parameters in my user model.
AuthController code:
class AuthController extends GetxController {
static AuthController instance = Get.find();
late Rx<User?> _user;
// Rx<model.User>? userModel;
Rx<model.User>? userModel = model.User().obs; //ERROR CAUSING LINE**
#override
void onReady() {
super.onReady();
_user = Rx<User?>(firebaseAuth.currentUser);
_user.bindStream(firebaseAuth.authStateChanges());
ever(_user, _setInitialScreen);
}
_setInitialScreen(User? user) {
if (user == null) {
Get.offAll(() => LoginScreen());
} else {
// userModel?.bindStream(listenToUser());
Get.offAll(() => const HomeScreen());
userModel?.bindStream(listenToUser());
print(userModel);
}
}
// registering the user
void registerUser(String username, String email, String password) async {
try {
if (username.isNotEmpty && email.isNotEmpty && password.isNotEmpty) {
// save our user to our auth and firebase firestore
UserCredential cred = await firebaseAuth.createUserWithEmailAndPassword(
email: email,
password: password,
);
model.User user = model.User(
name: username, email: email, uid: cred.user!.uid, cart: []);
await firestore
.collection('users')
.doc(cred.user!.uid)
.set(user.toJson());
} else {
Get.snackbar(
'Error Creating Account',
'Please enter all the fields',
);
}
} catch (e) {
Get.snackbar(
'Error Creating Account',
e.toString(),
);
}
}
void loginUser(String email, String password) async {
try {
if (email.isNotEmpty && password.isNotEmpty) {
await firebaseAuth.signInWithEmailAndPassword(
email: email, password: password);
print('log success');
} else {
Get.snackbar(
'Error Logging in',
'Please enter all the fields',
);
}
} catch (e) {
Get.snackbar(
'Error Logging in',
e.toString(),
);
}
}
updateUserData(Map<String, dynamic> data) {
print("UPDATED");
firestore.collection('users').doc(_user.value?.uid).update(data);
}
Stream<model.User> listenToUser() => firestore
.collection('users')
.doc(_user.value?.uid)
.snapshots()
.map((snapshot) => model.User.fromSnap(snapshot));
}
User model code:
class User {
// static const UID = "uid";
// static const NAME = "name";
// static const EMAIL = "email";
String uid;
String name;
String email;
List<CartItemModel> cart;
User(
{required this.name,
required this.email,
required this.uid,
required this.cart});
Map<String, dynamic> toJson() =>
{"name": name, "email": email, "uid": uid, "cart": cart};
// static User fromSnap(DocumentSnapshot snap) {
static User fromSnap(DocumentSnapshot snap) {
var snapshot = snap.data() as Map<String, dynamic>;
return User(
name: snapshot['name'],
email: snapshot['email'],
uid: snapshot['uid'],
cart: _convertCartItems(snapshot['cart'] ?? []));
}
// List<CartItemModel> _convertCartItems(List cartFromDb) {
static List<CartItemModel> _convertCartItems(List cartFromDb) {
List<CartItemModel> _result = [];
// logger.i(cartFromDb.lengt);
print(cartFromDb.length);
cartFromDb.forEach((element) {
_result.add(CartItemModel.fromMap(element));
});
return _result;
}
}
Add ? operator to tell explicity that the object can be null.
So the code goes like:
class User {
String? uid;
String? name;
String? email;
List<CartItemModel>? cart;
}

Unhandled Exception: Converting object to an encodable object failed: Instance of 'LoginModel'

Am still learning and understanding the working of flutter, I am trying to save json string whenever a user logins in for the First time, and use the ID and token to call and interact with different API endpoints. Whenever I try to save the json content to Shared Preference I end with error
Unhandled Exception: Converting object to an encodable object failed:
Instance of 'LoginModel'
My LoginModel
import 'dart:convert';
LoginModel loginModelFromJson(String str) => LoginModel.fromJson(json.decode(str));
String loginModelToJson(LoginModel data) => json.encode(data.toJson());
class LoginModel {
LoginModel({
this.id,
this.username,
this.email,
this.roles,
this.userid,
this.surname,
this.firstname,
this.telephoneno,
this.whatsappno,
this.active,
this.studyrole,
this.tokenType,
this.accessToken,
});
int id;
String username;
String email;
List<String> roles;
String userid;
String surname;
String firstname;
String telephoneno;
String whatsappno;
int active;
String studyrole;
String tokenType;
String accessToken;
factory LoginModel.fromJson(Map<String, dynamic> json) => LoginModel(
id: json["id"],
username: json["username"],
email: json["email"],
roles: List<String>.from(json["roles"].map((x) => x)),
userid: json["userid"],
surname: json["surname"],
firstname: json["firstname"],
telephoneno: json["telephoneno"],
whatsappno: json["whatsappno"],
active: json["active"],
studyrole: json["studyrole"],
tokenType: json["tokenType"],
accessToken: json["accessToken"],
);
Map<String, dynamic> toJson() => {
"id": id,
"username": username,
"email": email,
"roles": List<dynamic>.from(roles.map((x) => x)),
"userid": userid,
"surname": surname,
"firstname": firstname,
"telephoneno": telephoneno,
"whatsappno": whatsappno,
"active": active,
"studyrole": studyrole,
"tokenType": tokenType,
"accessToken": accessToken,
};
}
how am trying to save the Json to shared pref when user clicks on the login button
login(username, password) async {
SharedPref sharedPref = SharedPref();
LoginModel userSave = LoginModel();
final String url = "http://21.76.45.12:80/data/api/auth/signin"; // iOS
final http.Response response = await http.post(
url,
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(<String, String>{
'username': username,
'password': password,
}),
);
print(response.body);
sharedPref.save("user", userSave);
}
My Login button Widget
RoundedButton(
text: "LOGIN",
press: () async {
if (_formKey.currentState.validate()) {
progressDialog.show();
await login(
username,
password,
);
SharedPreferences prefs =
await SharedPreferences.getInstance();
String token = prefs.getString("accessToken");
loadSharedPrefs();
print(token);
// ignore: null_aware_in_condition
if (token == null) {
progressDialog.hide();
showAlertsDialog(context);
// ignore: null_aware_in_condition
} else {
progressDialog.hide();
showAlertzDialog(context);
}
}
},
),
whenever I try to load the preference I get no data
loadSharedPrefs() async {
try {
LoginModel user = LoginModel.fromJson(await sharedPref.read("user"));
Scaffold.of(context).showSnackBar(SnackBar(
content: new Text("Loaded!"),
duration: const Duration(milliseconds: 500)));
setState(() {
userLoad = user;
});
} catch (Excepetion) {
Scaffold.of(context).showSnackBar(SnackBar(
content: new Text("Nothing found!"),
duration: const Duration(milliseconds: 500)));
}
}
My SharedPref class
class SharedPref {
read(String key) async {
final prefs = await SharedPreferences.getInstance();
return json.decode(prefs.getString(key));
}
save(String key, value) async {
final prefs = await SharedPreferences.getInstance();
prefs.setString(key, json.encode(value));
}
remove(String key) async {
final prefs = await SharedPreferences.getInstance();
prefs.remove(key);
}
}
what am I doing wrong such that the JSON is not being saved to shared prefs? Thank you for the help
You are not parsing the json anywhere in your code. You are creating an empty object using:
LoginModel userSave = LoginModel();
Which contains null values for the properties and that's why you are getting those exceptions. You want to parse the json and create the object using:
LoginModel userSave = loginModelFromJson(response.body);
sharedPref.save("user", userSave);

The method '[]' was called on null: firebase flutter

I need to retrieve User Data from Firebase and use a builder to pass on the data to UI. When I run the apps, I method is called in on Null.
I tried many ways to call firebase data but I keep receive error message on provider or on calling the data NULL.
The error is most likely coming from the method _getProfileData() below.
_getProfileData(AuthNotifier authNotifier) async {
final uid = await Provider.of(context, listen: false).authNotifier.getCurrentUID();
await Provider.of(context, listen: false)
.collection('Users')
.document(uid)
.get().then((result) {
user.isAdmin = result.data['isAdmin'];
});
}
When I made the changes below by using Provider, another error appears with Provider not working.
final uid = await Provider.of<authNotifier>(context, listen: false).getCurrentUID();
I placed the getter in the API.
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
// GET UID
Future<String> getCurrentUID(User user, AuthNotifier authNotifier) async {
return (await _firebaseAuth.currentUser()).uid;
}
// GET CURRENT USER
Future getCurrentUser(User user, AuthNotifier authNotifier) async {
return await _firebaseAuth.currentUser();
}
Stream<String> get onAuthStateChanged => auth.onAuthStateChanged.map(
(FirebaseUser user) => user?.uid,
);
I structured User Data as below.
class User {
List favorites = [];
String documentID;
String displayName;
String email;
String password;
bool isAdmin;
User({
this.favorites,
this.documentID,
this.displayName,
this.email,
this.password,
this.isAdmin,
});
factory User.fromFirestore(DocumentSnapshot document) {
Map data = document.data;
return User(
favorites: data['favorite'] ?? [],
documentID: document.documentID,
displayName: data['displayName'] ?? '',
email: data['email'] ?? '',
isAdmin: data['isAdmin'] ?? false,
);
}
// get admin => null;
Map<String, dynamic> toMap() {
return {
'displayName': displayName,
'email': email,
'isAdmin': isAdmin,
};
}
}

Flutter Firestore Issue: Not able to store Sign Up form data in Cloud Firestore DB, instead hard coded data is getting stored

DatabaseService Class
class DatabaseService {
final String uid;
DatabaseService({this.uid});
//collection reference
final CollectionReference agentsCollection =
Firestore.instance.collection('agents');
Future updateUserData(
String fullname,
String phonenumber,
String email,
String profession,
String city
)
async {
return await agentsCollection.document(uid).setData({
'fullname': fullname,
'phonenumber': phonenumber,
'email': email,
'profession': profession,
'city': city,
});
}
AuthService Class
class AuthService {
final FirebaseAuth _auth = FirebaseAuth.instance;
//create user object based on FirebaseUser
User _userFromFirebaseUser(FirebaseUser user) {
return user != null ? User(uid: user.uid) : null;
}
//auth change user stream
Stream<User> get user {
return _auth.onAuthStateChanged
.map(_userFromFirebaseUser);
}
Then I have a function to Register the user in this class as below:
//Register with email and password
Future registerWithEmailAndPassword(String email, String password) async {
try{
AuthResult result = await _auth.createUserWithEmailAndPassword
(email: email, password: password);
FirebaseUser user = result.user;
//create a new document for the user with the uid
await DatabaseService(uid: user.uid).updateUserData( 'hardcoded Name',
'Hardcoded Number','hardcoded email', 'hardcoded profession', 'hardcoded city');
return _userFromFirebaseUser(user);
} catch(e){
print(e.toString());
return null;
}
}
SignUp Class
In this class I call the user (uid) using Provider service. Then I use the function from the AuthService Class which uses the function from the DatabaseService class in order to create a new document in the Database.
RaisedButton(
elevation: 5.0,
padding: EdgeInsets.only(left: 60, right: 60 , top: 15, bottom:15),
color: Colors.blue,
child: Text(
'Sign Up',
style: TextStyle(color: Colors.white),
),
onPressed: () async {
if(_formKey.currentState.validate()){
setState(() => loading= true);
dynamic result = await _auth.registerWithEmailAndPassword(email, password);
await DatabaseService (uid: user.uid).updateUserData(this.fullname,
this.phonenumber, this.email, this.profession, this.city);
if(result == null) {
setState(() {
error = 'please supply a valid email';
loading = false;
});
} else {
Navigator.push(context, new MaterialPageRoute(
builder: (context) => SignIn()
));
}
}
}
),
So Given all this, for some reason it's only storing the hard coded data from the AuthService class and not performing the line in the SignUp class under the onPressed() function; where I am telling it to use the function updateUserData and store the this.email, this.fullname, etc. Also an important note, in the SignUp class it says returned null user (assuming uid).
Please someone help me if you get what I am doing wrong in this context.
I think when parsing the data the hard coded data remains. here is an example of how to fix it.
create a user obj
class User {
final String userID;
final String displayName;
final String email, pushToken;
final String phoneNumber;
final String profilePictureURL;
User({
this.phoneNumber,
this.userID,
this.pushToken,
this.displayName,
this.email,
this.profilePictureURL,
});
Map<String, Object> toJson() {
return {
'pushToken': pushToken,
'phoneNumber': phoneNumber,
'userID': userID,
'displayName': displayName,
'email': email == null ? '' : email,
'profilePictureURL': profilePictureURL,
'appIdentifier': 'my app'
};
}
factory User.fromJson(Map<String, Object> doc) {
User user = new User(
pushToken: doc['pushToken'],
userID: doc['userID'],
displayName: doc['displayName'],
phoneNumber: doc['phoneNumber'],
email: doc['email'],
profilePictureURL: doc['profilePictureURL'],
);
return user;
}
factory User.fromDocument(DocumentSnapshot doc) {
return User.fromJson(doc.data);
}
}
and then the sign up method
//user sign up
static Future<String> signUp(String email, String password) async {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
FirebaseUser user = (await _firebaseAuth.createUserWithEmailAndPassword(
email: email, password: password))
.user;
return user.uid;
}
//if user id doesnt exist add user
static void addUser(User user) async {
checkUserExist(user.userID).then((value) {
if (!value) {
print("user ${user.displayName} ${user.email} added");
Firestore.instance
.document("users/${user.userID}")
.setData(user.toJson());
Fluttertoast.showToast(
msg: "user ${user.displayName} ${user.email} added");
} else {
print("user ${user.displayName} ${user.email} exists");
}
});
}
//check if user exists
static Future<bool> checkUserExist(String userID) async {
bool exists = false;
try {
await Firestore.instance.document("users/$userID").get().then((doc) {
if (doc.exists)
exists = true;
else
exists = false;
});
return exists;
} catch (e) {
return false;
}
}
and to handle your button onPressed: and it will save your data to firestore
await signUp(email, password).then((uID) {
addUser(new User(
userID: uID,
email: email,
displayName: fullname,
phoneNumber: number,
pushToken: pushToken,
profilePictureURL: ''));
Hey #Ggriffo i used this code in the onPressed function:
dynamic result = await _auth.registerWithEmailAndPassword
(email, password).then((user) {
DatabaseService (uid: user.uid).updateUserData(this.fullname,
this.phonenumber, this.email, this.profession, this.city);
});
and now it works! i used this logic from your onPressed piece of code. Thanks!

Registering User using Flutter and PHP Laravel and saving User info with SharedPreferrence

I am trying to save result from json to SharedPreferrence but i keep getting Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'
This is my Code
_register(BuildContext context, User user) async {
var _userService = UserService();
var registeredUser = await _userService.createUser(user);
var encodeFirst = json.encode(registeredUser.body);
var result = json.decode(encodeFirst);
if(result['result'] == true){
SharedPreferences _prefs = await SharedPreferences.getInstance();
_prefs.setInt("userId", result["user"]["id"]);
_prefs.setString("userName", result["user"]["name"]);
_prefs.setString("userEmail", result["user"]["email"]);
Navigator.push(
context, MaterialPageRoute(builder: (context) => CheckoutScreen(cartItems: this.widget.cartItems,)));
} else {
_showSnackMessage(Text('Failed to register the user!', style: TextStyle(color: Colors.red),));
}
}
this is my User, UserService and Repository file
class User{
int id;
String name;
String email;
String password;
toJson(){
return{
'id': id.toString(),
'name': name,
'email': email,
'password': password
};
}
}
class UserService {
Repository _repository;
UserService(){
_repository = Repository();
}
createUser(User user) async{
return await _repository.httpPost('register', user.toJson());
}
}
httpPost(String api, data) async {
return await http.post(_baseUrl + "/" + api, body: data);
}
var encodeFirst = json.encode(registeredUser.body); will call User toJson()
And in toJson() , you have set 'id': id.toString(),
when you do var result = json.decode(encodeFirst);
It's actually a string not int
Correct toJson() please see below
// To parse this JSON data, do
//
// final user = userFromJson(jsonString);
import 'dart:convert';
User userFromJson(String str) => User.fromJson(json.decode(str));
String userToJson(User data) => json.encode(data.toJson());
class User {
int id;
String name;
String email;
String password;
User({
this.id,
this.name,
this.email,
this.password,
});
factory User.fromJson(Map<String, dynamic> json) => User(
id: json["id"],
name: json["name"],
email: json["email"],
password: json["password"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"email": email,
"password": password,
};
}