how can I read data from firebase firestory by getx
I make all models and controllers and try to read data, but something is wrong
class ContollerBinding extends Bindings{
#override
void dependencies() {
Get.lazyPut(() => DetailController());
Get.lazyPut(() => DetailModel());
}
}
class DetailController extends GetxController {
List<DetailModel> get detailModel => _detailModel;
List<DetailModel> _detailModel = [];
final CollectionReference _detialCollectionReference = FirebaseFirestore.instance.collection('detail');
DetailController(){
getDetail();
}
getDetail() async {
_detialCollectionReference.get().then((value) {
for (int i= 0 ; i< value.docs.length ;i++){
_detailModel.add(DetailModel.fromJson(value.docs[i].data())); //error here
}
update();
});
}
}
class DetailModel {
String? name;
String? title;
String? text;
String? img;
String? time;
String? prize;
DetailModel({ this.name, this.title, this.text, this.img, this.time, this.prize ,});
DetailModel.fromJson(Map<dynamic, dynamic>?map, data){
if (map == null){
return;
}
name = map['name'];
title = map['title'];
text = map['text'];
img = map['img'];
time = map['time'];
prize = map['prize'];
}
toJson (){
return {
name = 'name',
title = 'title',
text = 'text',
img = 'img',
time = 'time',
prize = 'prize',
};
}
}
I can't figure out where is the problem and I see a lot of videos and do like him, but it seems a problem
Gets a list of all the documents included in this snapshot.
2 positional argument(s) were expected, but 1 found.
Try adding the missing arguments.dartnot_enough_positional_arguments
The function can't be unconditionally invoked because it can be 'null'.
Try adding a null check ('!').dartunchecked_use_of_nullable_value
enter image description here
Related
I have a collection in Firebase that I am trying to retrieve and add to a list:
I also have an events model defined. Before adding the event to a list, I would like to create an Event object using the data read from Firebase.
event_model:
class Event {
String eid;
String title;
String location;
String start;
String end;
String instructor;
String image;
String description;
Event({
required this.eid,
required this.title,
required this.location,
required this.start,
required this.end,
required this.instructor,
required this.image,
required this.description
});
String getEid() {
return eid;
}
String getTitle() {
return title;
}
String getLocation() {
return location;
}
String getStart() {
return start;
}
String getEnd() {
return end;
}
String getInstructor() {
return instructor;
}
String getImage() {
return image;
}
String getDescription() {
return description;
}
void setEid(String eid) {
this.eid = eid;
}
void setTitle(String title) {
this.title = title;
}
void setLocation(String location) {
this.location = location;
}
void setStart(String start) {
this.start = start;
}
void setEnd(String end) {
this.end = end;
}
void setInstructor(String instructor) {
this.instructor = instructor;
}
void setImage(String image) {
this.image = image;
}
void setDescription(String description) {
this.description = description;
}
}
This is what I have so far. I am creating the list of Event objects then trying to get the entire collection and for each document in the collection, I am creating the Event object and trying to add it to the list. I am not sure if this is correct.
List<Event> _events = [];
Future<UserProfile> getUserProfile() async {
try {
final FirebaseAuth auth = FirebaseAuth.instance;
final snapshot = await FirebaseFirestore.instance.collection('events').get();
snapshot.docs.forEach((doc) {
Map<String, dynamic>? data = snapshot.data();
Event event = Event(
eid: data?['eid'],
title: data?['title'],
...
});
a better approach for this is that the conversation of the Map<String, dynamic> to an Event class object, should be done using a factory constructor of the Event class, and setting a default value for each property so if something goes null, your app won't crash, it will have a default value and work fine, like this:
add this to your Event class:
factory Event.fromMap(Map<String, dynamic>? map) {
return Event(
eid: map?["eid"] ?? "defaultValue,"
title: map?["title"] ?? "defaultValue",
location: map?["location"] ?? "defaultValue",
start: map?["start"] ?? "defaultValue,"
end: map?["ends"] ?? "defaultValue,"
instructor: map?["instructor"] ?? "defaultValue,"
image: map?["image"] ?? "defaultValue,"
description: map?["description"] ?? "defaultValue",
);
}
then instead of implementing your methods, save yourself from the boilerplate code by using the:
Event event = Event.fromMap(snapshot.data() as Map<String, dynamic>);
_events.add(event);
I am getting data from Firebase Database and Adding it to a List of my Model class. I tested the incoming data by printing to Console and it works fine, but once i add the data to my model class, it disappears.
Here's my Provider class where i'm loading the data.
import 'package:firebase_database/firebase_database.dart';
import 'package:flutter/material.dart';
import 'package:local_stuffs_notification/apis/fcm.dart';
import 'package:local_stuffs_notification/models/request_model.dart';
import 'package:shared_preferences/shared_preferences.dart';
class IncomingRequest with ChangeNotifier {
List<RequestModel> _incomingRequests = [];
IncomingRequest(this._incomingRequests);
List<RequestModel> get incomingRequest {
return [..._incomingRequests];
}
Future<void> setIncomingRequest(RequestModel requestModel) async {
try {
DatabaseReference reference =
FirebaseDatabase.instance.ref("incomingRequests");
reference.child(requestModel.id).child(Fcm.getUid()).set(
{
"name": requestModel.name.toString(),
"phone": requestModel.phone.toString(),
"email": requestModel.email.toString(),
"fcmToken": requestModel.fcmToken.toString(),
},
);
notifyListeners();
} catch (error) {
rethrow;
}
}
Future<void> loadIncomingRequests() async {
try {
SharedPreferences preferences = await SharedPreferences.getInstance();
DatabaseReference reference = FirebaseDatabase.instance
.ref('incomingRequests/${preferences.getString('userId')!}');
Stream<DatabaseEvent> stream = reference.onValue;
stream.listen((DatabaseEvent event) {
print(event.snapshot.value);
final data = event.snapshot.value as Map;
print('data: $data');
final List<RequestModel> loadedRequest = [];
data.forEach(
(key, value) {
print('requestData: ${value['name']}');
loadedRequest.add(
RequestModel(
id: key.toString(),
name: value['name'].toString(),
fcmToken: value['fcmToken'].toString(),
phone: value['phone'].toString(),
email: value['email'].toString(),
),
);
print(loadedRequest);
},
);
_incomingRequests = loadedRequest;
print('LoadedRequests: $loadedRequest');
notifyListeners();
});
// reference.onValue.listen(
// (event) {
// if (event.snapshot.value == null) {
// return;
// }
// final data = event.snapshot.value as Map;
// final List<RequestModel> loadedRequests = [];
// data.forEach(
// (key, requestData) {
// loadedRequests.add(
// RequestModel(
// id: key,
// name: requestData['name'],
// fcmToken: requestData['fcmToken'],
// phone: requestData['phone'],
// email: requestData['email'],
// ),
// );
// },
// );
// _incomingRequests = loadedRequests;
// notifyListeners();
// },
//);
} catch (error) {
rethrow;
}
}
}
Here's my Model Class
class RequestModel {
final String id;
final String name;
final String fcmToken;
final String phone;
final String email;
RequestModel({
required this.id,
required this.name,
required this.fcmToken,
required this.phone,
required this.email,
});
}
I'm getting the data until i added it to loadedRequest List
Please help, i've spent hours on this and i don't know what i'm doing wrong. When i print the loadedRequest list, i get an empty list. Thanks.
Those logs aren't showing an empty list - It says [Instance of 'RequestModel']. That means there is a value there, but Dart simply doesn't know how to convert RequestModel to a String so that it can be printed out on the console.
An empty list would be printed simply as [], and if you had two values, for example, you would see [Instance of 'RequestModel', Instance of 'RequestModel'].
To print out your values with more detail, you can override the toString() method on your class.
For example:
class RequestModel {
final String id;
final String name;
final String fcmToken;
final String phone;
final String email;
RequestModel({
required this.id,
required this.name,
required this.fcmToken,
required this.phone,
required this.email,
});
#override
String toString() =>
"RequestModel(id: $id, name: $name, fcmToken: $fcmToken, phone: $phone, email: $email)";
}
take a look at the raw data once again, it contains all the users data so you need to get the access the uid before the name
final uid = FirebaseAuth.instance.currentUser!.uid;
and then for the RequestModel:
name: data[uid]['name']
Im currently using https://pub.dev/packages/file_picker for this function
FilePickerResult result =
await FilePicker.platform.pickFiles();
if (result != null) {
setState(() {
filePicked = result;
});
for (int i = 0; i < result.files.length; i++) {
setState(() {
listBytes.add(result.files[i].bytes);
});
}
} else {
// User canceled the picker
}
when i test on web it work successfully, however the problem occur when running on web app (in mobile) after select image it got no respond. It's hard to debug since i don't really know on how to debug for web app. My question is, can i just use the function i use on web, or is there any specific function i need to use in order for it to work in web app.
You can try this for the web app (This method should only be used for the web platform):
import '../../models/html_nonweb.dart'
if (dart.library.js) 'dart:html' as html;
Future<WebFileModel> pickWebFileModel() {
final completer = Completer<WebFileModel>();
final html.InputElement input =
html.document.createElement('input') as html.InputElement;
input
..type = 'file'
..accept = 'image/*';
input.onChange.listen((e) async {
final List<html.File> files = input.files!;
final reader = html.FileReader();
reader.readAsDataUrl(files.first);
reader.onError.listen(completer.completeError);
final Future<WebFileModel> resultsFutures =
reader.onLoad.first.then((_) => WebFileModel(
path: reader.result! as String,
type: files.first.type as String,
createdAt: DateTime.fromMillisecondsSinceEpoch(
files.first.lastModified!,
),
htmlFile: files.first,
));
final results = await resultsFutures;
completer.complete(results);
});
input.click();
return completer.future;
}
To use this code, you need to create the html_nonweb.dart file:
const document = Document();
class Document {
const Document();
Element createElement(String el) => InputElement();
}
class File {
final int? lastModified = null;
final String? type = null;
}
class Element {
const Element();
}
class InputElement extends Element {
const InputElement();
final List<File>? files = null;
Stream<Object> get onChange => Stream.empty();
set type(String type) {}
set multiple(bool multiple) {}
set accept(String s) {}
void readAsDataUrl(File file) {}
void click() {}
}
class FileReader {
Stream<void Function(Object error, [StackTrace? stackTrace])> get onError =>
Stream.empty();
void readAsDataUrl(File file) {}
Stream<Object> get onLoad => Stream.empty();
final Object? result = null;
}
And WebFileModel:
import 'dart:typed_data';
import 'html_nonweb.dart' if (dart.library.js) 'dart:html' as html;
class WebFileModel {
final String path;
final String type;
final DateTime createdAt;
final html.File? htmlFile;
final Uint8List? uIntFile;
WebFileModel({
required this.path,
required this.type,
required this.createdAt,
this.htmlFile,
this.uIntFile,
});
WebFileModel copyWith({
String? path,
String? type,
DateTime? createdAt,
html.File? htmlFile,
Uint8List? uIntFile,
}) {
return WebFileModel(
path: path ?? this.path,
type: type ?? this.type,
createdAt: createdAt ?? this.createdAt,
htmlFile: htmlFile ?? this.htmlFile,
uIntFile: uIntFile ?? this.uIntFile,
);
}
}
To get a Uint8List, you need to do the following:
final imageBase64 =media.path.replaceFirst(RegExp(r'data:image/[^;]+;base64,'), '');
final uIntFile = base64Decode(imageBase64);
I have two provider classes where as a property there is an instance of a Combo object.
My problem is when I modify value properties of Combo object of provider one, the instance of provider two is modified as well.
This is a problem for me because it makes me impossible to have two different instances even when they are created on different classes.
#immutable class Combo
{
Combo(
{
this.idCombo = 0,
this.idThirdCombo = 0,
this.name = '',
this.urlImage = '',
final List<int>? recipy,
final List<Product>? selectedRecipy,
final List<OptionalRecepy>? optionalRecepy,
final SwitStoreProductType? type,
}) :
this.recipy = recipy ?? [],
this.selectedRecipy = selectedRecipy ?? [],
this.optionalRecepy = optionalRecepy ?? [],
this.type = type ?? SwitStoreProductType.none;
final int idCombo;
final int idThirdCombo;
final String name;
final String urlImage;
final List<int> recipy;
final List<Product> selectedRecipy;
final List<OptionalRecepy> optionalRecepy;
final SwitStoreProductType type;
}
//Provider One
class ProductDetailsBSProvider extends ChangeNotifier
{
Combo? _currentCombo;
void modifyCombo(Product product, int index)
{
if(index != this._currentOptionIndex)
{
if(this._currentCombo!.selectedRecipy.length > 1)
{
int previousIndex = (this._currentCombo!.selectedRecipy.length - 1);
this._currentCombo!.selectedRecipy.removeAt(previousIndex);
this._currentCombo!.selectedRecipy.insert(previousIndex, product);
this._currentOptionIndex = index;
}
else
{
this._currentCombo!.selectedRecipy.add(product);
this._currentOptionIndex = index;
}
}
else
{
if(this._currentCombo!.selectedRecipy.length == 0)
{
this._currentCombo!.selectedRecipy.add(product);
}
else
{
this._currentCombo!.selectedRecipy.removeLast();
this._currentCombo!.selectedRecipy.add(product);
}
}
notifyListeners();
}
}
//Provider Two
class StoreProvider extends ChangeNotifier
{
Combo? _currentCombo;
}
If I print the _currentCombo properties value of Provider Two it will be exactly the same as Provider One
I have been working with my Store App, but this null safety is getting me pissed now. I have created a class but it gives me this error with later doesn't allow my app to work correctly
this is the the product.dart file:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:loja_virtual_nnananene/models/item_size.dart';
class Product extends ChangeNotifier {
Product.fromDocument(DocumentSnapshot document) {
id = document.documentID;
name = document['name'];
description = document['description'];
images = List<String>.from(document.data['images'] as List<dynamic>);
// ingore_for_file: Warning: Operand of null-aware operation
sizes = (document.data['sizes'] as List<dynamic> ?? [])
.map((s) => ItemSize.fromMap(s as Map<String, dynamic>))
.toList();
}
String id = "";
String name = "";
String description = "";
List<String> images = [];
List<ItemSize> sizes = [];
ItemSize _selectedSize;
ItemSize get selectedSize => _selectedSize;
set selectedSize(ItemSize value) {
_selectedSize = value;
notifyListeners();
}
}
I'm receiving an error at the Product.from...
This is the error:
Non-nullable instance field '_selectedSize' must be initialized.
Try adding an initializer expression, or add a field initializer in this constructor, or mark it 'late'.
This is my ItemSize class:
class ItemSize {
ItemSize.fromMap(Map<String, dynamic> map) {
name = map['name'] as String;
price = map['price'] as num;
stock = map['stock'] as int;
}
String name = "";
num price = 0;
int stock = 0;
bool get hasStock => stock > 0;
#override
String toString() {
return 'ItemSize{name: $name, price: $price, stock: $stock}';
}
}
Calling in main widget:
class SizeWidget extends StatelessWidget {
const SizeWidget(this.size);
final ItemSize size;
#override
Widget build(BuildContext context) {
final product = context.watch<Product>();
final selected = size == product.selectedSize;
Color color;
if (!size.hasStock)
color = Colors.red.withAlpha(50);
else if (selected)
color = ColorSelect.cprice;
the code tries to get the selected item the first time, and of course it will be null. The alternative I found was...
in ItemSize class, i create a construtor simple with all null -> ItemSize();
class ItemSize {
ItemSize.fromMap(Map<String, dynamic> map) {
name = map['name'] as String;
price = map['price'] as num;
stock = map['stock'] as int;
}
ItemSize();
String? name;
num? price;
int? stock;
bool get hasStock => stock! > 0;
#override
String toString() {
return 'ItemSize{name: $name, price: $price, stock: $stock}';
}
}
in the Product class do the get this way.
ItemSize get selectedSize {
if (_selectedSize != null)
return _selectedSize!;
else
return ItemSize();
}