Somehow, I can't get this code to work:
My model is this:
class Location {
final String name;
final String route;
final String id;
final GeoPoint location;
final List images;
final String address;
Location(
{this.name,
this.route,
this.id,
this.location,
this.images,
this.address});
}
Here's the Firebase snapshot that works just fine without the location field.
List<Location> _locationListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.docs.map((doc) {
return Location(
name: doc["name"]["ru"] ?? '',
route: doc["route"] ?? '',
address: doc["address"]["ru"] ?? '',
images: doc["images"],
id: doc['id'] ?? '',
location: doc["location"]);
}).toList();
}
Here's the error thrown:
Unhandled Exception: Bad state: field does not exist within the DocumentSnapshotPlatform
Since the code works fine without the location field, then it means that the location field does not exist in the document.
Related
Is there any way to get user properties without querying the database?
I have the following two screens:
sign up (this is where I save the users info to firebase)
chat (this is where I need the users information)
This is the snip of the code from the sign-up screen:
// variable that calls the firebase class that holds all the logic
late final FirebaseCloudStorage _userService;
// function that creates user
Future createUserAccount() async {
if (_photo == null) return;
try {
setState(() {
_isLoading = true;
});
await AuthService.firebase().createUser(
email: _email.text,
password: _password.text,
);
final userId = AuthService.firebase().currentUser?.id;
final destination = 'user-profile-image/$userId';
final ref = FirebaseStorage.instance.ref(destination);
await ref.putFile(_photo!);
imageUrl = await ref.getDownloadURL();
_userService.createNewUser(
userId: userId as String,
userState: 'new',
userImage: imageUrl as String,
userFirstName: _userFirstName.text,
userLastName: _userLastName.text,
userCellNumber: _userCellphoneNumber.text,
userCity: _userCity.text,
userAreaCode: _userAreaCode.text,
userAddress: _userAddress.text,
userEmail: _email.text,
);
Below is the class that has all the cloud user logic:
#immutable
class CloudUser {
final String documentId;
final String userId;
final String userState;
final String userImage;
final String userFirstName;
final String userLastName;
final String userCellNumber;
final String userCity;
final String userAreaCode;
final String userAddress;
final String? userEmail;
const CloudUser({
required this.documentId,
required this.userId,
required this.userState,
required this.userImage,
required this.userFirstName,
required this.userLastName,
required this.userCellNumber,
required this.userCity,
required this.userAreaCode,
required this.userAddress,
required this.userEmail,
});
// I TRIED CALLING THIS BUT IT DOESN'T WORK!
// I TRIED CALLING IT FROM THE CHAT SCREEN LIKE SO:: CloudUser.getFirstName()
String getFirstName() {
return userFirstName;
}
CloudUser.fromSnapshot(QueryDocumentSnapshot<Map<String, dynamic>> snapshot)
: documentId = snapshot.id,
userId = snapshot.data()[userIdColumn],
userState = snapshot.data()[userStateColumn] ?? "",
userImage = snapshot.data()[userImageColumn] ?? "",
userFirstName = snapshot.data()[userFirstNameColumn] ?? "",
userLastName = snapshot.data()[jobAreaCodeColumn] ?? "",
userCellNumber = snapshot.data()[userCellNumberColumn] ?? "",
userCity = snapshot.data()[userCityColumn] ?? "",
userAreaCode = snapshot.data()[userAreaCodeColumn] ?? "",
userAddress = snapshot.data()[userAddressColumn] ?? "",
userEmail = snapshot.data()[userEmailColumn] ?? "";
}
Class that holds logic to interact with FirebaseCloudStorage:
class FirebaseCloudStorage {
final user = FirebaseFirestore.instance.collection('user');
Future<CloudUser> createNewUser({
required String userId,
required String userState,
required String userImage,
required String userFirstName,
required String userLastName,
required String userCellNumber,
required String userCity,
required String userAreaCode,
required String userAddress,
required String userEmail,
}) async {
final document = await user.add({
userIdColumn: userId,
userStateColumn: userState,
userImageColumn: userImage,
userFirstNameColumn: userFirstName,
userLastNameColumn: userLastName,
userCellNumberColumn: userCellNumber,
userCityColumn: userCity,
userAreaCodeColumn: userAreaCode,
userAddressColumn: userAddress,
userEmailColumn: userEmail,
});
final fetchedUser = await document.get();
return CloudUser(
documentId: fetchedUser.id,
userId: userId,
userState: userState,
userImage: userImage,
userFirstName: userFirstName,
userLastName: userLastName,
userCellNumber: userCellNumber,
userCity: userCity,
userAreaCode: userAreaCode,
userAddress: userAddress,
userEmail: userEmail,
);
}
// I can add a class to call the server to get the user data using the user id, but I don't think I need to do that
// singleton
static final FirebaseCloudStorage _shared =
FirebaseCloudStorage._sharedInstance();
FirebaseCloudStorage._sharedInstance();
factory FirebaseCloudStorage() => _shared;
}
So.... is there any way I can efficiently store and retrieve that data?
you can get some properties easily by adding them to the account info, and some of the allowed fields are:
displayName
email
phoneNumber
photoURL
so instead of querying your collection, you can get the current firebase user which will return a datatype of User and the user comes with these properties if you've set them during sign up
e.g
User? _currentUser = FirebaseAuth.instance.currentUser;
//for display name
_currentUser?.displayName;
//for email
_currentUser?.email;
//for phoneNumber
_currentUser?.phoneNumber;
//for profile picture
_currentUser?.photoURL;
I have two model classes, StudentRecords, and Records. The StudentRecords class has a variable Records as a Lists. I have a Firestore collection named studentRecords in which I want to add data from StudentRecords class, and Records should be an array inside that collection. I am using Getx as my state management. Let me post the model classes first.
class RecordModel extends Equatable {
final String? juz;
final String? page;
final String? surah;
final String? ayat;
final double? grade;
const RecordModel({
this.juz,
this.page,
this.surah,
this.ayat,
this.grade,
});
Next is StudentRecords model class.
class StudentRecords extends Equatable {
String? studentId;
double? avgGrade;
Timestamp? createdOn;
String? createdBy;
String? createdById;
List<RecordModel>? recordsModel;
DocumentReference? documentReference;
StudentRecords({
required this.studentId,
required this.avgGrade,
required this.createdOn,
required this.createdBy,
required this.createdById,
required this.recordsModel,
});
#override
List<Object?> get props =>
[studentId, avgGrade, createdOn, createdBy, createdById, recordsModel];
StudentRecords copyWith({
String? studentId,
double? avgGrade,
Timestamp? createdOn,
String? createdBy,
String? createdById,
List<RecordModel>? murajaatRecords,
}) {
return StudentRecords(
studentId: studentId ?? this.studentId,
avgGrade: avgGrade ?? this.avgGrade,
createdOn: createdOn ?? this.createdOn,
createdBy: createdBy ?? this.createdBy,
createdById: createdById ?? this.createdById,
recordsModel: murajaatRecords ?? recordsModel,
);
}
Map<String, dynamic> toJson() {
return {
'studentId': studentId,
'avgGrade': avgGrade,
'createdOn': createdOn,
'createdBy': createdBy,
'createdById': createdById,
'murajaatRecords':
List<RecordModel>.from(recordsModel!.map((e) => e.toJson())),
};
}
Next is my firebase firestore function to add data to the collection.
Future<void> addStudentRecord(
{required double? avgGrade,
Timestamp? createdOn,
String? createdBy,
required List<RecordModel> recordsModel}) async {
// getting path to the studentRecords
DocumentReference docRef = _firebaseFirestore
.collection(FirestoreConstants.pathUserCollection)
.doc(_firebaseAuth.currentUser!.uid)
.collection('studentRecords')
.doc();
// getting name of the signed in user
final docSnapshot =
await _collectionReference.doc(_firebaseAuth.currentUser!.uid).get();
if (docSnapshot.exists) {
Map<String, dynamic>? data = docSnapshot.data();
var createdBy = data?[FirestoreConstants.name];
StudentRecords StudentRecords = StudentRecords(
studentId: documentReference!.id,
avgGrade: avgGrade,
createdOn: Timestamp.now(),
createdBy: createdBy,
createdById: _firebaseAuth.currentUser!.uid,
recordsModel: recordsModel,
);
FirebaseFirestore.instance.runTransaction((transaction) async {
transaction.set(docRef, studentRecords.toJson());
});
}
}
Next, is my getx function in the controller class.
final recordModel = <RecordModel>[].obs;
void addStudentRecord() async {
try {
await _firestoreFunctions
.addStudentRecord(
avgGrade: averageGrade.value, recordsModel: recordModel)
.then((value) => Get.snackbar('Success', 'Record Added Successfully',
snackPosition: SnackPosition.BOTTOM));
} on FirebaseException catch (e) {
if (kDebugMode) {
print("Firebase Exception: $e");
}
}
}.
What I am looking for is something like the sample given in the image below (ignore the array field name).
.
I am missing something very vital here, which is why the data is not getting added to the database. I am unable to figure it out. Please help. If any further information is needed, let me know. Thanks.
I got this problem for long time ago trying to resolve this issue I saw many places at internet but not able to solve this problem to get the info from the API call from the controller class. Because of this kind of error I saw in docs flutter maybe because the flutter package that is also a dart package I got the SDK 3.0.0 here's the code please someone to help me achieve this project thank you so much:
This is the model class:
class Product {
int? _totalSize;
int? _typeId;
int? _offset;
late List<ProductModel> _products;
List<ProductModel> get products => _products;
Product({required totalSize, required typeId, required offset, required products}){
this._totalSize = totalSize;
this._typeId = typeId;
this._offset = offset;
this._products = products;
}
factory Product.fromJson(Map<String, dynamic> json) {
var list = json['products'] as List;
List<ProductModel> productsList = list.map((e) => ProductModel.fromJson(e as Map<String, dynamic>)).toList();
return Product(
totalSize : json['total_size'] as int,
typeId : json['type_id'] as int,
offset : json['offset'] as int,
products: productsList
);
}
}
class ProductModel {
int? id;
String? name;
String? description;
int? price;
int? stars;
String? img;
String? location;
String? createdAt;
String? updatedAt;
int? typeId;
ProductModel(
{required this.id,
required this.name,
required this.description,
required this.price,
required this.stars,
required this.img,
required this.location,
required this.createdAt,
required this.updatedAt,
required this.typeId});
factory ProductModel.fromJson(Map<String, dynamic> json) {
return ProductModel(
id: json['id'] as int,
name: json['name'] as String,
description: json['description'] as String,
price: json['price'] as int,
stars: json['stars'] as int,
img: json['img'] as String,
location: json['location'] as String,
createdAt: json['createdAt'] as String,
updatedAt: json['updatedAt'] as String,
typeId: json['typeId'] as int
);
}
}
This is the controller class:
import 'dart:convert';
import 'package:get/get.dart';
import 'package:licores_app/data/repository/category_product_repo.dart';
import '../models/products_model.dart';
class CategoryProductController extends GetxController {
final CategoryProductRepo categoryProductRepo;
CategoryProductController({required this.categoryProductRepo});
List<dynamic> _categoryProductList = [];
// Get Method from Product Model
List<dynamic> get CategoryProductList => _categoryProductList;
// Response from repo product method
Future<void> getCategoryProductList() async {
Response response = await categoryProductRepo.getCategoryProductList();
print('got the products'); // This is right to this point
if (response.statusCode == 200) {
// Init to null not to repeat
_categoryProductList = [];
_categoryProductList.addAll(Product
.fromJson(jsonDecode(response.body))
.products); // --> Here the
// Unhandled Exception: type 'Null' is not a subtype of type 'String'
print(_categoryProductList);
update();
} else { // I added the curly braces but took off because I was
// debugging the problem still persist!
print('not able to get product list json');
}
}
}
And this is the error:
[ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type 'Null' is not a subtype of type 'String'
E/flutter ( 6243): #0 CategoryProductController.getCategoryProductList (package:licores_app/controllers/category_product_controller.dart:27:72)
E/flutter ( 6243): <asynchronous suspension>
You are accepting null data, so you dont need to force with as.
You can format like
name: json['name']
factory ProductModel.fromJson(Map<String, dynamic> json) {
return ProductModel(
id: int.tryParse("${json['id']}"),
name: json['name'],
description: json['description'],
price: int.tryParse("${json['price']}"),
stars: json['stars'],
img: json['img'],
location: json['location'],
createdAt: json['createdAt'],
updatedAt: json['updatedAt'],
typeId: int.tryParse("${json['typeId']}"));
}
try this:
factory ProductModel.fromJson(Map<String, dynamic> json) {
return ProductModel(
id: json['id'] as int,
name: json['name'] as String ?? '',
description: json['description'] as String ?? '',
price: json['price'] as int ?? '',
stars: json['stars'] as int ?? '',
img: json['img'] as String ?? '',
location: json['location'] as String ?? '',
createdAt: json['createdAt'] as String ?? '',
updatedAt: json['updatedAt'] as String ?? '',
typeId: json['typeId'] as int ?? 0
);
}
Ok, well add this to your code:
if (response.statusCode == 200) {
// Init to null not to repeat
_categoryProductList = [];
//Added lines:
//----------------------------
print('response.body is ${response.body}');
print('of type: ${response.body.runtimeType}');
print('jsonDecode(response.body) is ${jsonDecode(response.body)}');
print('of type: ${jsonDecode(response.body).runtimeType}');
print('Product.fromJson(jsonDecode(response.body)) is ${Product.fromJson(jsonDecode(response.body))}');
print('of type: ${Product.fromJson(jsonDecode(response.body)).runtimeType}');
print('Product.fromJson(jsonDecode(response.body).products is ${Product.fromJson(jsonDecode(response.body)).products}');
print('of type: ${Product.fromJson(jsonDecode(response.body)).products.runtimeType}');
//----------------------------
_categoryProductList.addAll(Product
.fromJson(jsonDecode(response.body))
.products); // --> Here the
// Unhandled Exception: type 'Null' is not a subtype of type 'String'
print(_categoryProductList);
update();
} else { // I added the curly braces but took off because I was
// debugging the problem still persist!
print('not able to get product list json');
}
and tell me what it prints!
First you have to check are you getting response code 200. Then checked following way
First you make all fields in ProductModel class is optional (null acceptable).
then in constructor you have remove required work because you make it as option field, and in factory constructor there is no required an additional type casting like as Int, as String, just remove it.
After this you must varified all key in factory return class ( constructor of production class ). Simply i mean check your all key of json and verify further your all data type with json you received from Api or somewhere else.
Hope this will helpfull.
You need to print out response.body and add this here then it will be quite obvious which field needs to be optional.
A statement such as this one:
img: json['img'] as String,
will produce the error message type 'Null' is not a subtype of type 'String' when the json object does not define the key 'img'
So one of the keys that you are parsing is undefined.
In order to figure out which one, we need to know what the response looks like exactly.
Then remove all the "as String" casts on fields that are optional from the server.
I'm trying to create a function to return the articles list from the Firebase Realtime Database.
But it's not working.
I'm new to flutter.
My Database structure is like the following:
Below is the code I have written for that:
Future<List<ArticleModel>> getArticles() async {
List<ArticleModel> articles = [];
uid = FirebaseAuth.instance.currentUser!.uid;
var ref = FirebaseDatabase.instance.ref().child("saved").child(uid);
await ref.once().then((DatabaseEvent databaseEvent) {
var docs = databaseEvent.snapshot.children;
for (var element in docs) {
Map<dynamic, dynamic> data = jsonDecode(jsonEncode(element.value));
var article = ArticleModel.fromJson(Map<dynamic, dynamic>.from(data));
articles.add(article);
}
});
print(articles);//Its printing [Instance of 'ArticleModel', Instance of 'ArticleModel'.......
return articles;
}
Code for ArticleModel
class ArticleModel {
String sourceName;
String author;
String title;
String description;
String url;
String urlToImage;
String publishedAt;
ArticleModel(
{required this.sourceName,
required this.author,
required this.title,
required this.description,
required this.urlToImage,
required this.url,
required this.publishedAt});
factory ArticleModel.fromJson(Map<dynamic, dynamic> element) {
return ArticleModel(
author: element['author'],
description: element['desc'],
sourceName: element['source'],
publishedAt: element['time'],
title: element['title'],
url: element['url'],
urlToImage: element['urlImage'],
}
}
The problem is that you ArticleModel has a different fields name in the method .fromJson() from the data structure in the database, which is the dec key, you have written it in the model as desc.
So change:
description: element['desc'],
in ArticleModel to be:
description: element['dec'],
This is my userdata.dart
class UserData{
late String name;
late String age;
UserData({
this.name = "",
this.age = "",
});
factory UserData.fromJson(Map<String, dynamic> parsedJson) {
return new UserData(
name: parsedJson['Name'],
age: parsedJson['Age'],
);
}
The provider.dart:
Future getPatient(
String uId, BuildContext context) async {
uId = '60aa563cb2bd01aaeb5a94ac';
http.Response user =
await http.get(Uri.https("link.com", "getUser/$uId"));
var userJson = jsonDecode(user.body);
print("Patient data: ${userJson}"); /// code works till here as it prints
UserData users = new UserData.fromJson(userJson);
print("Patient Name ${users.name[0]}");
return patients;
}
}
User model
{_id: {$oid: 60aa563cb2bd01aaeb5a9sdfs}, Email: xyz#gmail.com, Name: pqr, Age: 20, Gender: Male, Phone: 23478917883}
I want to retrieve the data for every id (name and age of the user). When I'm trying to retrieve the data, I'm facing this error.
Error: Expected a value of type 'String', but got one of type 'int'
I'm new to flutter and Stackoverflow. Can you please help me in telling what is the issue and how can I solve it?
This error means that one of the fields that you are parsing is an int but you are initializing it to a variable of type String
In your data Age and Phone are int
So make the following changes in your model class
class UserData{
String? name;
int? age; //change this to int from String
UserData({
#required this.name,
#required this.age,
});
factory UserData.fromJson(Map<String, dynamic> parsedJson) {
return new UserData(
name: parsedJson['Name'],
age: parsedJson['Age'],
);
}
}