I have an application where i need to save data in real time database , i have setup code for authentication , storage and realtime database , auth and storage work fine but not the latter ,
i have tried different approach to make realtime db work but unfortunately nothing was successful , any help would be appreciated guys thank you.
This is how i init firebase
FirebaseApp app;
void main() async {
WidgetsFlutterBinding.ensureInitialized();
app = await Firebase.initializeApp(
name: 'SecondaryApp',
options: const FirebaseOptions(
appId: '1:729669525962:android:b878xxxxxxxxxxxxx',
apiKey: 'AIzaSyD0w6UnBrWxxxxxxxxxxxxxxxxxxxxxx',
databaseURL: 'https://xxxxxxxxxxxx.appspot.com',
messagingSenderId: 'xxxxxxxxxxxxxxxx',
projectId: 'groceryfxxxxxxxxf6'
)
);
runApp(MaterialApp(
home: UserRegistrationScreen(),
debugShowCheckedModeBanner: false,
));
}
part 2
class _UserRegistrationScreenState extends State<UserRegistrationScreen> {
DatabaseReference itemRef;
final firebaseAuth = FirebaseAuth.instance;
final storage = FirebaseStorage.instance;
#override
void initState() {
super.initState();
itemRef = FirebaseDatabase.instance.reference().child('Users');
}
This is how i save data
BuyerModel model = new BuyerModel(
fullName,phone,country,state,city,address,
email,'online','Buyer', downloadUrl,DateTime.now().microsecondsSinceEpoch.toString(),
firebaseAuth.currentUser.uid);
itemRef.child(firebaseAuth.currentUser.uid).set(model);
This is the buyer model
class BuyerModel {
String fullName;
String phone;
String country;
String state;
String city;
String address;
String email;
String status;
String accountType;
String profileImage;
String timeStamp;
String userUid;
BuyerModel(this.fullName,this.phone,this.country,this.state,this.city,
this.address,this.email,this.status,this.accountType,this.profileImage,
this.timeStamp,this.userUid);
}
In Flutter I don't think the Firebase SDK knows how to write custom classes like BuyerModel. I usually end up with fromSnapshot and toMap methods to map back and forth.
An example of such a class:
class Question {
HUser owner;
String title;
List<String> answers;
int timeInSeconds;
String key;
Question(String this.title, List<String> this.answers, this.timeInSeconds, { this.owner }) {
}
Map<String, dynamic> toMap() {
return <String,dynamic>{
"owner": owner?.uid,
"title": title,
"answers": answers,
"timeInSeconds": timeInSeconds
};
}
Question.fromSnapshot(DataSnapshot snapshot): assert(snapshot != null),
title = snapshot.value["title"],
timeInSeconds = snapshot.value["timeInSeconds"],
owner = snapshot.value["owner"] != null ? HUser(snapshot.value["owner"]) : null,
key = snapshot.key;
}
I see now that I still need to read the answers back from the snapshot. That might explain a bug in my app. 😄
Related
I'm new to flutter and firebase (and yes i know this question has been asked before).
But i've seen plenty of different ways to map firebase data into provider, and some reason cannot get a single to work.
I have this data structure. And all i wish, is to Map it into an class / object.
Firebase screenshot
This is my data model.dart:
#immutable
class Requests {
Requests({
this.name = '',
this.pairingId = 0,
});
final String name;
final double pairingId;
Requests.fromJson(Map<String, Object?> json)
: this(
name: json['name']! as String,
pairingId: json['pairingId'] as double,
);
Map<String, Object?> toJson() {
return {
'name': name,
'pairingId': pairingId,
};
}
}
#immutable
class UserDataTest with ChangeNotifier {
UserDataTest({
this.firstName = '',
this.lastName = '',
this.gender = '',
this.dateOfBirth,
this.userUID = '',
this.uidp = '',
this.pairingId = 0,
this.requests = const [],
});
UserDataTest.fromJson(Map<String, Object?> json)
: this(
firstName: json['firstName']! as String,
lastName: json['lastName']! as String,
gender: json['gender']! as dynamic,
dateOfBirth: json['dateOfBirth']! as DateTime?,
userUID: json['userUID']! as String,
uidp: json['uidp']! as String,
pairingId: json['pairingId']! as double,
requests: json['requests']! as List<Requests>,
);
late final String firstName;
final String lastName;
final dynamic gender;
final DateTime? dateOfBirth;
final String userUID;
final String uidp;
final double pairingId;
final List<Requests> requests;
Map<String, Object?> toJson() {
return {
'firstName': firstName,
'lastName': lastName,
'gender': gender,
'dateOfBirth': dateOfBirth,
'userUID': userUID,
'uidp': uidp,
'pairingId': pairingId,
'requests': requests,
};
}
}
But from here i dont have any solution that works just partly.
Again, my wish is to be able to just write, ex. user.firstName and display the first Name. How do i get to there?
I know im missing the call to firebase, but i haven't been successful in making one.
I dont know if have to do something inside the provider.
(Yes i have a multiprovider at the top of my tree
and a call to the provider where im using it or wanting to)
My suggestion: start over. Just start by creating a simple class manually with just a few of the fields from Firebase, and work your way out. For example use the UserDataTest and just make it a class:
class UserDataTest {
String? firstName;
String? lastName;
UserDataTest({ this.firstName, this.lastName });
factory UserDataTest.fromJson(Map<String, dynamic> json) {
return UserDataTest(
firstName: json['firstName'],
lastName: json['lastName'],
);
}
}
Try to keep these classes as plain as possible. Create other classes for your services and then make those extend ChangeNotifier, like to encapsulate your business logic and trigger notifications.
Then, from Firebase you will easily be able to do stuff like:
List<UserDataTest> userData = [];
FirebaseFirestore.instance.collection('userdata').get().then((QuerySnapshot snapshot) {
userData = snapshot.docs.map((doc) => UserDataTest.fromJson(doc.data())).toList();
});
My two cents.
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
I have the following auth provider, and I can sign the user in and the app state changes. But when I do a sign in I notice that nothing is stored in the local storage and when I refresh the page the authStateChanges gives null for the user. I also just tried tho get the current user as a Future which also returns null. What am I doing wrong?
const String oneTimePasswordFunctionName = "requestOneTimePassword";
const String signInWithOneTimePasswordFunctionName = "signInWithOneTimePassword";
class FirebaseAuthProvider extends AuthProvider {
final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;
final FirebaseFunctions _firebaseFunctions = FirebaseFunctions.instance;
Stream<AuthUser> get user {
return _firebaseAuth.authStateChanges().asyncMap((firebaseUser) {
//firebaseUser is always null on refresh
return firebaseUser == null ? AuthUser.empty : firebaseUser.toUser();
});
}
Future<void> requestOneTimePassword({required String email}) async {
final data = {"email": email};
final cloudFunction = _firebaseFunctions.httpsCallable(oneTimePasswordFunctionName);
await cloudFunction.call(data);
}
Future<void> signInWithOneTimePassword({required String email, required String oneTimePassword}) async {
final data = {"email": email, "oneTimePassword": oneTimePassword};
final cloudFunction = _firebaseFunctions.httpsCallable(signInWithOneTimePasswordFunctionName);
final result = await cloudFunction.call(data);
final jwt = result.data["data"]["jwt"] as String;
if (jwt.isEmpty) return;
await FirebaseAuth.instance.setPersistence(Persistence.LOCAL);
await _firebaseAuth.signInWithCustomToken(jwt);
}
Future<void> signOut() async {
try {
await _firebaseAuth.signOut();
} on Exception {
throw SignOutException();
}
}
}
extension on User {
FutureOr<AuthUser> toUser() async {
final tokenResult = await this.getIdTokenResult(true);
final claims = tokenResult.claims?.map<String, String>((key, value) => MapEntry(key, value.toString()));
return AuthUser(
id: uid,
email: Email.dirty(email ?? ''),
name: displayName ?? '',
photoURL: Uri.parse(photoURL ?? ''),
claims: claims ?? const {},
);
}
}
I really need it to work with the authStateChanges stream, because I want it also to work when the user does a sign out.
I am using the firebase auth emulator. This is my main
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await FirebaseAuth.instance.useAuthEmulator("localhost", 9099);
FirebaseFirestore.instance.settings = Settings(
host: "localhost:8080",
sslEnabled: false,
persistenceEnabled: false,
);
FirebaseFunctions.instance.useFunctionsEmulator("localhost", 5001);
Future<dynamic> Function() initializeFirebase = () async {
if (Firebase.apps.length == 0) await Firebase.initializeApp();
};
await Future.wait([
initializeFirebase(),
EasyLocalization.ensureInitialized(),
]);
runApp(_buildAppWithDependencies());
}
I am testing in the latest version of google chrome
Versions
flutter: 2.5.3 (stable)
firebase_core: ^1.10.0
firebase_auth: ^3.2.0
The method 'document' isn't defined for the type 'CollectionReference'.
Try correcting the name to the name of an existing method, or defining a method named 'document'.
I am getting this error in my project. Can you help me?
My Code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:crypto_app/models/users.dart';
class FireStoreService {
final FirebaseFirestore _firestore = FirebaseFirestore.instance;
final DateTime time = DateTime.now();
Future<void> createUser({id, mail, userName, photoUrl = ""}) async {
await _firestore.collection("users").doc(id).set({
"userName": userName,
"mail": mail,
"photoUrl": photoUrl,
"about": "",
"createTime": time
});
}
Future<Users> bringUser(id) async {
DocumentSnapshot doc = await _firestore.collection("users").doc(id).get();
if (doc.exists) {
Users users = Users.dokumandanUret(doc);
return users;
}
return null;
}
void userUpdate({String userId, String userName, String photoUrl = ""}) {
_firestore
.collection("users")
.document(userId)
.updateData({"userName": userName, "photoUrl": photoUrl});
}
}
CollectionReference in cloud_firestore for flutter/dart does not have a document(..) method. It is called doc(..) instead. https://pub.dev/documentation/cloud_firestore/latest/cloud_firestore/CollectionReference/doc.html
I am developing a Flutter app with Firebase Database. This is a chat app. The database structure I need is as the following.
So, I first create a chat room and then add its members. Here please consider the key 900 as a key in chat_room (i know its not in this example), acting as the foreign key in members node. According to the current structure, I can add any number of members to a chat room and I can easily find them without downloading lot of data. This is achievable by the following code.
fire_database_service.dart
import 'package:firebase_database/firebase_database.dart';
class FireDatabaseService
{
final DatabaseReference _chatRoomReference = FirebaseDatabase.instance.reference().child('chat_room');
//Create chat_room
Future<String> createChatRoom({String lastMessage, String chatMode}) async {
var newChatRoomRef = _chatRoomReference.push();
var newChatRoomKey = newChatRoomRef.key;
await newChatRoomRef.set({
'last_message': lastMessage,
'chat_mode': chatMode,
'timestamp': DateTime.now().millisecondsSinceEpoch,
});
return newChatRoomKey;
}
Future<void> addChatMembers(List<ChatMember> chatMembers, String chatRoomID) async
{
for(int i=0; i<chatMembers.length; i++)
{
ChatMember chatMemeber = chatMembers[i];
var newChatMemberReference = FirebaseDatabase.instance.reference().child('members/$chatRoomID/').push();
var newChatMemberKey = newChatMemberReference.key;
await newChatMemberReference.set({
'email': chatMemeber.email,
'userID': chatMemeber.userID,
'user_role': chatMemeber.userRole,
});
}
return null;
}
}
chat.dart
void initState() {
super.initState();
FireDatabaseService firebaseDatabase = FireDatabaseService();
String chatRoomID="";
firebaseDatabase.createChatRoom(
lastMessage: "Test",
chatMode: "Supplier").then((value) async{
print("CHAT ID: "+value);
ChatMember member1 = new ChatMember(
email: "someone#test.com",
userRole: "customer",
userID: 30
);
ChatMember member2 = new ChatMember(
email: "anotherone#test.com",
userRole: "supplier",
userID: 50
);
List<ChatMember> chatMemberList = [member1, member2];
print("BEFORE");
await firebaseDatabase.addChatMembers(chatMemberList, "900");
print("AFTER");
});
}
Please note that in this line await firebaseDatabase.addChatMembers(chatMemberList, "900"); I am hardcoding the value 900. Instead of this, if I pass the unique key of the chat room node, I get this structure, which is completely incorrect of what i need.
I actually need this unique key of chat room to be in members node, so it will act as the foreign key in members node.
Why is this happening and how can I fix this?
I fixed this issue. It was because the chatRoomID is not getting the unique key, it was empty. I fixed it in the following way.
void initState() {
super.initState();
FireDatabaseService firebaseDatabase = FireDatabaseService();
firebaseDatabase
.createChatRoom(lastMessage: "Test", chatMode: "Supplier")
.then((value) async {
print("CHAT ID: " + value);
ChatMember member1 = new ChatMember(
email: "someone#test.com",
userRole: "customer",
userID: 30,
profilePic: "");
ChatMember member2 = new ChatMember(
email: "anotherone#test.com", userRole: "supplier", userID: 50);
List<ChatMember> chatMemberList = [member1, member2];
print("BEFORE");
await firebaseDatabase.addChatMembers(chatMemberList, value);
print("AFTER");
});
}