Failed to get uid to use within DatabaseService class in flutter - firebase

I face a problem where I can't get the current user ID from my firebase. I've already make that every new user will have their own collection based on the UID like this:
void addImagetoFirestore() async {
final CollectionReference imageData = Firestore.instance.collection(uid);
This is my DatabaseService class
class DatabaseService {
final String uid;
DatabaseService({this.uid});
String useruid;
final FirebaseAuth auth = FirebaseAuth.instance;
//Collection reference
final CollectionReference warrantyCollection =
Firestore.instance.collection('user id here');
List<Picture> _warrantyListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.documents.map((doc) {
return Picture(
name: doc.data['product name'],
info: doc.data['info'],
url: doc.data['url'],
uid: doc.data['uid']);
}).toList();
}
Future updateUserData(String name) async {
return await warrantyCollection.document(uid).setData({'name': name});
}
Stream<List<Picture>> get picture {
return warrantyCollection.snapshots().map(_warrantyListFromSnapshot);
}
}
I've tried referring to this,
but it seem like I can't just make something like
final CollectionReference warrantyCollection = Firestore.instance.collection(useridmethod());
are there any other alternative that I can try?

Instead of getting uid as a parameter to class, fetch it in constructor because in your case final FirebaseAuth auth = FirebaseAuth.instance; is useless as I see.
try this;
DatabaseService(){
userId = auth.currentUser.uid;
}

Related

Firebase Flutter Riverpod: How do I get the documentID from Firebase when using Riverpod to map values across a model? Code Included

I need to get the documentID of my documents in a firebase collection. The documentID is NOT stored as a field within the document. The ID was chosen by Firebase on import.
The other fields like name, phone, fullAddress, all display perfectly. How do I tap into the auto-generated docID using my Map/Model?
Any guidance is greatly appreciated.
Services:
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'restaurant_model.dart';
final restaurantProvider = StreamProvider.autoDispose((ref) {
final service = ref.watch(restaurantServiceProvider);
return service.restaurantModel();
});
final restaurantServiceProvider = Provider<RestaurantService>((ref) {
final firebase = FirebaseFirestore.instance;
return RestaurantService(firebase);
});
class RestaurantService {
final FirebaseFirestore _firebase;
RestaurantService(this._firebase);
Stream<List<RestaurantModel>> restaurantModel() {
return _firebase.collection('restaurantsPensacola').snapshots().map((event) => event.docs.map((e) => RestaurantModel.fromFirebase(e.data())).toList());
}
}
Model
import 'package:cloud_firestore/cloud_firestore.dart';
class RestaurantModel {
final String? name;
final String? phone;
final String? fullAddress;
final String? yearsInBusiness;
final String? priceRange;
final String? websiteLink;
final String? documentID;
RestaurantModel({
required this.name,
required this.phone,
required this.fullAddress,
required this.yearsInBusiness,
required this.priceRange,
required this.websiteLink,
required this.documentID,
});
factory RestaurantModel.fromFirebase(Map<String, dynamic> restaurantModel) {
return RestaurantModel(
name: restaurantModel['name'],
phone: restaurantModel['phone'],
fullAddress: restaurantModel['fullAddress'],
yearsInBusiness: restaurantModel['yearsInBusiness'],
priceRange: restaurantModel['priceRange'],
websiteLink: restaurantModel['websiteLink'],
//THIS IS WHERE I AM LOST AS THIS GENERATES ERROR
//Instance members can't be accessed from a factory constructor.
documentID: restaurantModel[documentID],
);
}
}
The document ID can be accessed via e.id. For your RestaurantModel, you would probably want to rename it to restaurantId to be more accurate as to what it is describing, and just save the auto-generated document ID as the restaurantId at creation. You could also generate your own unique ID (with uuid package or something similar) and create a new document with that ID.
Example:
Future<dynamic> createRestaurantRecord(
String id, Map<String, dynamic> data) async {
return await _firestore.doc('restaurants/$id').set(data);
}
Your factory will not work as the documentID is not automatically stored with the rest of the doc's data.
I was able to meet with my mentor and was shown I can get the ID from Firebase by adding e.id after e.data.
Stream<List<RestaurantModel>> restaurantModel() {
return _firebase.collection('restaurantsPensacola').snapshots().map(
(event) => event.docs.map((e) => RestaurantModel.fromFirebase(e.data(), e.id)).toList());
}
Then, it was recommended that I change the names slightly to make it easier to differentiate values. You'll see how I incorporated the documentID from Firebase.
import 'package:cloud_firestore/cloud_firestore.dart';
class RestaurantModel {
final String? name;
final String? phone;
final String? fullAddress;
final String? yearsInBusiness;
final String? priceRange;
final String? websiteLink;
final String? id;
RestaurantModel({
required this.name,
required this.phone,
required this.fullAddress,
required this.yearsInBusiness,
required this.priceRange,
required this.websiteLink,
required this.id,
});
factory RestaurantModel.fromFirebase(
Map<String, dynamic> restaurantModel, String documentIDFromFirebase) {
return RestaurantModel(
name: restaurantModel['name'],
phone: restaurantModel['phone'],
fullAddress: restaurantModel['fullAddress'],
yearsInBusiness: restaurantModel['yearsInBusiness'],
priceRange: restaurantModel['priceRange'],
websiteLink: restaurantModel['websiteLink'],
id: documentIDFromFirebase,
);
}
}

The method 'getString' was called on null. Receiver: null Tried calling: getString("name")

I am having a error The method 'getString' was called on null.
Receiver: null
Tried calling: getString("name")
I already instantiated
firebaseFirestore = FirebaseFirestore.instance;
sharedPreferences = await SharedPreferences.getInstance();
class _HomePageState extends State<HomePage> {
HomepageBloc _bloc;
ScrollController _scrollController = ScrollController();
TextEditingController _userNameSearchController = TextEditingController();
String userName = sharedPreferences.getString(SharedPreferencesKey.name);
String userToken = sharedPreferences.getString(SharedPreferencesKey.token);
#override
void initState() {
super.initState();
_bloc = HomepageBloc(userToken);
}
#override
void dispose() {
super.dispose();
_bloc.dispose();
}
I don't know why I am getting this error, it would be wonderful if this error can be solved
The way you instantiating sharedPreferences = await SharedPreferences.getInstance(); needs to wait for instance of SharedPreferences. The easiest way is to use FutureBuilder to wait, something like:
FutureBuilder(
future: SharedPreferences.getInstance(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final sharedPreferences = snapshot.data;
String userName = sharedPreferences.getString(SharedPreferencesKey.name);
String userToken = sharedPreferences.getString(SharedPreferencesKey.token);
}
},
)
Also, you can handle it as you want. The main idea is to wait for the instance creation.
Define shared instance like this sharedPreferences = await SharedPreferences.getInstance(); and also add await to define the variable like
String userToken = await sharedPreferences.getString(SharedPreferencesKey.token);

Store array from cloud firestore into variable

I have a collection called users. Each document has the ids of posts they have saved in an array. Is it possible to put this array into a variable and have it in a Text() widget? Essentially the text widget output would look like this on screen oMqSYa97CteaDr19lZ5Ga6WO4jn8oPJREOcJWLI2.
I have searched for this solution, but haven't found any luck.
I've tried a few things, but usually end up with Instance of 'Future DocomentSnapshot'
you should share your code for us to learn what you did and why do you face with that oMqSYa97CteaDr19lZ5Ga6WO4jn8oPJREOcJWLI2. However, firstly, you should create a model like that
class UserData {
final String uid;
final String name;
final String sugars;
final int strength;
UserData({ this.uid, this.sugars, this.strength, this.name });
}
and an instance;
final CollectionReference UsersCollection =
FirebaseFirestore.instance.collection('users');
and you can use it like that ;
UserData _userDataFromSnapshot(DocumentSnapshot snapshot) {
return UserData(
uid: uid,
name: snapshot.data()['name'],
sugars: snapshot.data()['sugars'],
strength: snapshot.data()['strength'],
);
}
Stream<UserData> get userData {
return UsersCollection.doc(uid).snapshots().map(_userDataFromSnapshot);
}
finally;
UserData userData = snapshot.data.sugars;

How to assign a Future variable to a class getter in Flutter

I'm trying to read user data from Firebase via Streamer and assign them into properties of my User class. I have a FirabaseActions class doing firebase stuff. Here is the method that I use streamer to get data. It works perfectly, and print(user.data['userName']); give me the right result.
static Future<User> userDataStream(loggedInUserEmail) async {
final databaseReference = Firestore.instance;
User currentUser;
await for (var snapshot in databaseReference
.collection('users')
.where('email', isEqualTo: loggedInUserEmail)
.snapshots()) {
for (var user in snapshot.documents) {
print(user.data['userName']);
currentUser.userName = user.data['userName'];
currentUser.email = user.data['email'];
currentUser.userID = user.data['userID'];
currentUser.level = user.data['level'];
}
}
return currentUser;
}
The problem begin when I try to assign these user info to my class properties. Here is my User class. I got an error like below. It is about Future type but I can't handle it. What should I do?
Class 'Future' has no instance getter 'email'.
Receiver: Instance of 'Future'
Tried calling: email
class User {
String userName;
String userID;
String email;
int level;
User({this.userName, this.userID, this.level, this.email});
}
The first problem is that you cant assign an username like this
currentUser.userName = user.data['userName'];
Because currentUser is null. A simple solution to that is to replace
User currentUser; with User currentUser = User();
Second problem :
I think you should never search user by his email, rather by the UID that you get from
FirebaseUser user = await FirebaseAuth.instance.currentUser(),
So you would query for the user like this :
static Future<User> userDataStream() async {
final firestore = Firestore.instance;
final currentFirestoreUser = await FirebaseAuth.instance.currentUser();
User currentUser;
var query = await firestore
.collection('users')
.where('uid', isEqualTo: currentFirestoreUser.uid)
.getDocuments();
var user = query.documents.first.data;
currentUser = User(
userName: user['userName'],
userID: user['userID'],
level: user['level'],
email: user['email']);
return currentUser;
}
You could add UID as a method's parameter, or leave it inside the method.

Firestore query to variable to populate shared preferences

New to Flutter, and although I've been around code for many years, this is my first time actually developing. I've been trying to figure out how to query the Cloud Firestore and map one of those properties to a shared preference. Since my app is talking to the cloud firestore when a user logs in anyway, I feel like I can update my shared preferences with a few fields that will save me from having to call firestore everytime I want to retrieve that piece of information.
I created a class that represents the collection layout in the firestore
class FirestoreUser {
FirestoreUser(this.aboutMe, this.nickname);
final String aboutMe;
final String nickname;
factory FirestoreUser.fromMap(Map<String, dynamic> data) {
if (data == null) {
return null;
}
final String aboutMe = data['aboutMe'];
final String nickname = data['nickname'] ?? '';
return FirestoreUser(aboutMe, nickname);
}
Map<String, dynamic> toMap() {
return {
'aboutMe': aboutMe,
'nickname': nickname,
};
}
}
I also have a function that writes data to the Firestore collection. That works just fine.
What I'm having a hard time with is how do I query for "aboutMe" in the collection above? I'm using
a provider to get the uid, but how do I do something like this:
aboutMe = Firestore.query.tothatdocument
Here's what I have been working on so far:
final user = Provider.of<User>(context, listen: false);
final firestore = Provider.of<FirestoreService>(context, listen:false);
final firebaseUser = await FirebaseAuth.instance.currentUser();
final QuerySnapshot result = await Firestore.instance.collection('users').where('id', isEqualTo: firebaseUser.uid).getDocuments();
final List<DocumentSnapshot> documents = result.documents;
SharedPreferences prefs = await SharedPreferences.getInstance();
And I want to do something like this:
prefs.setString('aboutMe', 'thatAboutMeVariable);
Is this possible? I think I'm missing capturing the stream as a snapshot? but not to sure.
Thanks again!
I ended up creating a new class with functions to retrieve the fields that I wanted. I then assigned a variable to the results of that function.
Here's the call:
aboutMe = await FirestoreUserService(id: widget.id).getAboutMeFromFirestore();
Here's the class and function:
class FirestoreUserService {
FirestoreUserService({#required this.id});
final FirebaseFirestore firestore = FirebaseFirestore.instance;
CollectionReference users;
String aboutMe;
Future getAboutMeFromFirestore() async {
DocumentSnapshot ds = await FirebaseFirestore.instance.collection('users').doc(id).get();
aboutMe = ds.data()['aboutMe'];
//print('\nFirestore aboutMe is value: $aboutMe');
return aboutMe;
}
}

Resources