Display User Data From Map String Dynamic Using Provider - firebase

I am trying to Display Data on another Page I am Using provider to get the user data and put it to my model like this:
getUserData() async {
User user = FirebaseAuth.instance.currentUser!;
String value = user.uid;
return usersFirebaseReference.doc(value).snapshots().listen((event) {
if (event.data() != null) {
log("$event.data()");
final Map<String, dynamic> _userData = event.data() as Map<String, dynamic>;
userData = UserData.fromMap(_userData);
userData!.firebaseId;
} else {
print('User Data is Empty');
userData = null;
}
notifyListeners();
print('Update gotten from User Data');
});
}
I am getting Nul from the returning data whenever I try to display the data in homepage as such:
userDataCrudService.userData?.store
Please Is there anything I am doing wrong. I am new to flutter and firestore Please. Thank you.
Below is My Model:
class UserData {
bool? admin;
String? firebaseId;
String? username;
String? email;
String? password;
String? name;
String? store;
String? address;
String? phone;
UserData({
this.admin,
this.firebaseId,
this.username,
this.email,
this.password,
this.name,
this.store,
this.address,
this.phone,
});
Map<String, dynamic> toMap() {
return {
'admin': admin,
'firebaseId': firebaseId,
'username': username,
'email': email,
'password': password,
'name': name,
'store': store,
'address': address,
'phone': phone,
};
}
factory UserData.fromMap(Map<String, dynamic> map) {
return UserData(
admin: map['admin'],
firebaseId: map['firebaseId'],
username: map['username'],
email: map['email'],
password: map['password'],
name: map['name'],
store: map['store'],
address: map['address'],
phone: map['phone'],
);
}
String toJson() => json.encode(toMap());
factory UserData.fromJson(String source) =>
UserData.fromMap(json.decode(source));
}

I got it it is a mistake from me, I am trying to get current user id from firestore but it saved with it own document id, I solved it by saving the document id with the user id at signup.

Related

Flutter: _CastError (type 'Null' is not a subtype of type 'Map<String, dynamic>' in type cast)

When I create a new user the error (_CastError (type 'Null' is not a subtype of type 'Map<String, dynamic>' in type cast)) apears at User.fromSnap ...as Map<stringm,dynamic> and firebase creates the user auth but not the user data
Can you help me to add array of array of objects to firebase?
Thanks!
user.dart
class User {
final String uid;
final String name;
final List<Game> game;
User(
{required this.uid,
required this.name,
required this.game});
factory User.fromSnap(DocumentSnapshot snap) {
var snapShot = snap.data() as Map<String, dynamic>;
return User(
uid: snapShot['uid'],
name: snapShot['name'],
game: snapShot['game']);
}
Map<String, dynamic> toJson() => {
'uid': uid,
'name': name,
'game': game,
};
}
class Game{
String rolName;
bool alive;
Game({required this.rolName, required this.alive});
factory Game.fromSnap(Map<String, dynamic> snap) {
return Game(rolName: snap['rolName'], alive: snap['alive']);
}
}
auth.dart
class AuthMethods with ChangeNotifier {
...
Future<String> singUpUser(
{required String email,
required String password,
required String namee}) async {
String res = 'Error';
try {
if (email.isNotEmpty ||
password.isNotEmpty ||
name.isNotEmpty ) {
UserCredential cred = await _auth.createUserWithEmailAndPassword(
email: email, password: password);
model.User _user = model.User(
uid: cred.user!.uid,
name: name,
game: [model.Game(rolName: 'default', alive: false)]);
await _firestore
.collection("users")
.doc(cred.user!.uid)
.set(_user.toJson());
res = 'success';
} else {
res = "Please enter all the fields";
}
} catch (err) {
res = err.toString();
}
return res;
}
Your factory looks right. But you're sending it nothing...the snap is null is what that error is telling you.

Flutter Firestore: Building my model from a snapshot

I'm struggling to build my model from firestore map. It seems basic yet I can't figure it out.
Here's my code :
firestore_service.dart
{
// ...
final FirebaseFirestore _db = FirebaseFirestore.instance;
await _db
.collection('Users')
.doc('jWtp19r7g2b4wwMJ5yBi')
.get()
.then((snapshot) {
print(snapshot);
print(snapshot.runtimeType);
final _data = snapshot.data() ?? {};
print(_data);
print(_data['uid']);
final user = UserModel.fromJson(_data);
print(user.uid);
return user;
});
}
user_model.dart
import 'package:flutter/material.dart';
class UserModel {
// ...
factory UserModel.fromJson(Map<String, dynamic> json) {
return UserModel(
uid: json['uid'],
username: json['username'],
characterID: json['character_id'],
);
}
}
Terminal
Can anyone help me?
Okay so, I don't know if it's a "clean" way of doing it but I figured I could add another factory in my model to build specifically from Firestore.
Since the specific error was Unhandled Exception: type 'List<dynamic>' is not a subtype of type 'List<String>', I duckduckgo-ed the error and found this solution :
service.dart
await _db
.collection('Users')
.doc('jWtp19r7g2b4wwMJ5yBi')
.get()
.then((snapshot) {
final _data = Map<String, dynamic>.from(snapshot.data() ?? {});
print(_data.runtimeType);
final user = UserModel.fromFirestore(_data);
print(user.uid);
});
user_model.dart
class UserModel {
UserModel({
required this.uid,
required this.characterID,
this.username,
});
final String uid;
final String? username;
final List<String> characterID;
factory UserModel.fromJson(Map<String, dynamic> json) {
return UserModel(
uid: json['uid'],
username: json['username'],
characterID: json['character_id'],
);
}
factory UserModel.fromFirestore(Map<dynamic, dynamic> json) {
return UserModel(
uid: json['uid'],
username: json['username'],
characterID: List<String>.from(json['character_id']),
);
}
Map<String, dynamic> toJson() => {
"uid": uid,
"username": username,
"character_id": characterID,
};
}
I feel like it's not my factory's role to "filter / cast" the data but that's the only way I found it working.

How to store list dynamic field data to existing collection on Firebase using Flutter

I have create some dynamic fields for user to submit their exam which are subject and grades. I know how to loop the data and store it in an array and display it as a JSON string format but I don't know how to store the data to an existing collection on Firebase.
Please guide me to fix this problem.
Here is the function code :
saveSPMResultToFirebase() async {
User? currentUser = FirebaseAuth.instance.currentUser;
List entries = [];
for (int i = 0; i < forms.length; i++) {
final subjectId = i.toString();
final subjectName = nameTECs[i].text;
final subjectGrade = gradeTECs[i];
entries.add(SPMModel(
subjectId: subjectId,
subjectName: subjectName,
subjectGrade: subjectGrade
));
}
await FirebaseFirestore.instance
.collection("users")
.doc(currentUser!.uid)
.update({'spmResult': entries.toString()});
//debugPrint(entries.toString());
}
Here is the model I used to store the data as json string format
class SPMModel {
String? subjectId;
String? subjectName;
String? subjectGrade;
SPMModel({this.subjectId, this.subjectName, this.subjectGrade});
//receive data from database
factory SPMModel.fromJson(map) {
return SPMModel(
subjectId: map['subjectId'],
subjectName: map['subjectName'],
subjectGrade: map['subjectGrade'],
);
}
#override
String toString() {
return '{subjectId: $subjectId, subjectName: $subjectName, subjectGrade: $subjectGrade}';
}
}
Here is the model of the existing collection
class UserProfileModel {
String? uid;
String? email;
String? fullName;
String? nric;
String? age;
String? gender;
String? ethnicity;
String? religion;
String? address;
String? state;
String? country;
String? phone;
String? parentName;
String? parentPhone;
String? spmResult;
UserProfileModel({
this.uid,
this.email,
this.fullName,
this.nric,
this.age,
this.gender,
this.ethnicity,
this.religion,
this.address,
this.state,
this.country,
this.phone,
this.parentName,
this.parentPhone,
this.spmResult,
});
//receive data from database
factory UserProfileModel.fromMap(map) {
return UserProfileModel(
uid: map['uid'],
email: map['email'],
fullName: map['fullName'],
nric: map['nric'],
age: map['age'],
gender: map['gender'],
ethnicity: map['ethnicity'],
religion: map['religion'],
address: map['address'],
state: map['state'],
country: map['country'],
phone: map['phone'],
parentName: map['parentName'],
parentPhone: map['parentPhone'],
spmResult: map['spmResult']
);
}
//send data to database
Map<String, dynamic> toMap() {
return {
'uid': uid,
'email': email,
'fullName': fullName,
'nric': nric,
'age': age,
'gender': gender,
'ethnicity': ethnicity,
'religion': religion,
'address': address,
'state': state,
'country': country,
'phone': phone,
'parentName': parentName,
'parentPhone': parentPhone,
'spmResult': spmResult
};
}
}
For now this is the progress that I made. It successfully stored to Firebase but as a string. Not as a sub data of the existing collection.
I have solved my own problem.
Dynamic field model
class SPMModel {
String? subjectName;
String? subjectGrade;
SPMModel(this.subjectName, this.subjectGrade);
Map<String, dynamic> toMap() => {
"subjectName": subjectName,
"subjectGrade": subjectGrade,
};
}
User Model (I created a list dynamic field array on existing collection model)
class UserProfileModel {
List<dynamic> spmResult = [];
//send data to database
Map<String, dynamic> toMap() {
return {
'spmResult': spmResult
};
}
}
submit Function (store to firebase)
saveSPMResultToFirebase() async {
User? currentUser = FirebaseAuth.instance.currentUser;
SPMModel spmModel;
for (int i = 0; i < forms.length; i++) {
final subjectName = nameTECs[i].text;
final subjectGrade = gradeTECs[i];
spmModel = SPMModel(subjectName, subjectGrade);
await FirebaseFirestore.instance
.collection("users")
.doc(currentUser!.uid)
.update({
"spmResult": FieldValue.arrayUnion([spmModel.toMap()])
});
}
}
Output

How to match Firebase User UID with Firestore Doc ID - Flutter

I am new to flutter. So Please kindly bear with me.
I am creating a Real Estate App using Firebase and Provider.
I have two root Collections (1) "users" and (2) "properties"
I would like to achieve one specific task.
Although it seems like a simple task, yet I am still unable to solve it.
The task is to store Firebase User UID as Firestore Document ID of the rool Collection called "users" when the user sign up.
The problem I am having is the Firestore Document ID is automatically generated and its not Firebase User UID. Plus the field for userId appears null in Firestore.
Please see the screenshot of my database here
Thank you for your attention and time.
Here is my user_model.dart
class NayyaaUser {
String? uid;
String name;
String email;
String? phone;
NayyaaUser({this.uid, required this.name, required this.email, this.phone});
//send data to Firestore
Map<String, dynamic> toMap() {
return {
'userId': uid,
'userName': name,
'userEmail': email,
'userPhone': phone,
};
}
//draw data from firestore
factory NayyaaUser.fromFirestore(Map<String, dynamic> firestore) =>
NayyaaUser(
uid: firestore['userId'],
email: firestore['userEmail'] ?? " ",
name: firestore['userName'] ?? " ",
phone: firestore['userPhone'] ?? " ",
);
}
Here is my user_provider.dart
class UserProvider extends ChangeNotifier {
final firestoreService = FirestoreService();
final authService = AuthService();
String? _userId;
String? _name;
String? _email;
String? _phone;
//getters
String? get userId => _userId;
String? get name => _name;
String? get email => _email;
String? get phone => _phone;
//setters
changeName(String value) {
_name = value;
notifyListeners();
}
changeEmail(String value) {
_email = value;
notifyListeners();
}
changePhone(String value) {
_phone = value;
notifyListeners();
}
saveUserProfile() {
if (_userId == null) {
var updateUserProfile = NayyaaUser(
// userId: _userId,
uid: _userId,
name: name ?? '',
email: email ?? '',
phone: phone ?? '');
firestoreService.saveUserDataToFirestore(updateUserProfile);
} else {
var newUserProfile = NayyaaUser(
// userId: _userId,
uid: _userId,
name: name ?? '',
email: email ?? '',
phone: phone ?? '');
firestoreService.saveUserDataToFirestore(newUserProfile);
}
}
}
Here is auth_service.dart
class AuthService {
final FirebaseAuth _authInstance = FirebaseAuth.instance;
//create user obj based on "User" from Firebase
NayyaaUser? _userFromFirebase(User? user) {
return user != null
? NayyaaUser(
uid: user.uid,
name: '',
email: '',
phone: '',
)
: null;
}
// auth change user stream
Stream<NayyaaUser?> get userAuthStatus {
return _authInstance.authStateChanges().map(_userFromFirebase);
}
// sign in with email + password
Future signIn(String email, String password) async {
try {
UserCredential userAuthResult = await _authInstance
.signInWithEmailAndPassword(email: email, password: password);
User? user = userAuthResult.user;
return _userFromFirebase(user!);
} catch (e) {
// ignore: avoid_print
print(e.toString());
return null;
}
}
Future signUp(String email, String password) async {
try {
UserCredential userAuthResult = await _authInstance
.createUserWithEmailAndPassword(email: email, password: password);
User? user = userAuthResult.user;
return _userFromFirebase(user);
} catch (e) {
print(e.toString());
return null;
}
}
// sign out
Future signOut() async {
try {
return await _authInstance.signOut();
} catch (e) {
// ignore: avoid_print
print(e.toString());
return null;
}
}
}
Here is firestore_service.dart
class FirestoreService {
final CollectionReference _userRef =
FirebaseFirestore.instance.collection('users');
final CollectionReference _propertyRef =
FirebaseFirestore.instance.collection('properties');
//add or update user to firestore
Future<void> saveUserDataToFirestore(NayyaaUser nayyaaUserData) {
return _userRef.doc(nayyaaUserData.uid).set(nayyaaUserData.toMap());
}
// fetch user data from firestore
Stream<List<NayyaaUser>> getNayyaaUser() {
return _userRef.snapshots().map((snapshot) => snapshot.docs
.map((document) =>
NayyaaUser.fromFirestore(document.data() as Map<String, dynamic>))
.toList());
}
}
After login/signup successfully you can get user id from FirebaseAuth.instance.currentUser?.uid

How to get a Stream of lists of objects "Stream<List<MyModel>>" in dart or flutter?

I want to get a Stream<List<MyModel>> and use it in a StreamBuilder later on.
But I have a problem getting the stream from firebase.
Here is my function to get the stream:
static Stream<List<Exercise>> getExercisesWithUpdates() {
Stream<QuerySnapshot<Object?>> querySnapshot = _firestore.collection('exercise').snapshots(); //hier kein null
Stream<List<Exercise>> test = querySnapshot.map((document) {
return document.docs.map((e) {
Exercise.fromJson(e.data() as Map<String, dynamic>);
}).toList();
});
return test;
}
Error message: The return type 'List<Null>' isn't a 'List<Exercise>', as required by the closure's context.
I think this is due to null safety but I am not sure how to handle this case.
For this example my Exercise class:
class Exercise {
String? id;
String? name;
String? imageName;
String? imageUrl;
String? description;
Exercise({required this.id, required this.name, this.imageName, this.imageUrl, this.description});
Exercise.empty();
Exercise.fromJson(Map<String, dynamic> json)
: this(
id: json['id']! as String,
name: json['name']! as String,
imageName: json['imageName']! as String,
imageUrl: json['imageUrl']! as String,
description: json['description']! as String);
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'imageName': imageName,
'imageUrl': imageUrl,
'description': description,
};
}
}
You're missing a return statement in map:
return document.docs.map((e) {
return Exercise.fromJson(e.data() as Map<String, dynamic>);
}).toList();

Resources