Hello i am trying to get data from firestore map it to a stream i am using Rxdart how do i add this Stream of list of product to the stream.When i tried to do it it keeps saying.The argument type Stream> can't be assigned to parameter type List.I am new to flutter please help.
Product Service;
class ProductService {
Firestore _db = Firestore.instance;
var random = Random();
Stream<List<Product>> fetchProducts() {
return _db.collection('products').snapshots().map(
(snapshot) => snapshot.documents
.map((document) => Product.fromFirestore(document.data))
.toList(),
);
}
}
bloc
class ProductBloc {
final _products = BehaviorSubject<List<Product>>();
final ProductService _db = ProductService();
//getters
Stream<List<Product>> get products => _products.stream;
Function(List<Product>) get changeProducts => _products.sink.add;
loadData() async {
try {
var products = _db.fetchProducts();
_products.sink.add(products);
} catch (err) {
print(err);
}
}
dispose() {
_products.close();
}
}
Related
I have a problem, my database has data, but I can't list this data in the application, can you see where the problem is?
Here the database query is being implemented
#override
Stream<Either<TodoFailures, List<Todo>>> watchAll() async* {
//yield left(const InsufficientPermissions());
// users/{user ID}/notes/{todo ID}
final userDoc = await firestore.userDocument();
yield* userDoc.todoCollection
.snapshots()
.map((snapshot) => right<TodoFailures, List<Todo>>(snapshot.docs
.map((doc) => TodoModel.fromFirestore(doc).toDomain()).toList()))
.handleError((e) {
if (e is FirebaseException) {
if (e.code.contains('permission-denied') || e.code.contains("PERMISSION_DENIED")) {
return left(InsufficientPermisssons());
} else {
return left(UnexpectedFailure());
}
} else {
// ? check for the unauthenticated error
// ! log.e(e.toString()); // we can log unexpected exceptions
return left(UnexpectedFailure());
}
});
}
Below is where I capture the integrated query through the BloC
#injectable
class ObserverBloc extends Bloc<ObserverEvent, ObserverState> {
final TodoRepository todoRepository;
StreamSubscription<Either<TodoFailures, List<Todo>>>? todoStreamSubscription;
ObserverBloc({required this.todoRepository}) : super(ObserverInitial()) {
on<ObserverEvent>((event, emit) async {
emit(ObserverLoading());
await todoStreamSubscription?.cancel();
todoStreamSubscription = todoRepository
.watchAll()
.listen((failureOrTodos) => add(TodosUpdatedEvent(failureOrTodos: failureOrTodos)));
});
on<TodosUpdatedEvent>((event, emit) {
event.failureOrTodos.fold((failures) => emit(ObserverFailure(todoFailure: failures)),
(todos) => emit(ObserverSuccess(todos: todos)));
});
}
#override
Future<void> close() async {
await todoStreamSubscription?.cancel();
return super.close();
}
}
Even containing data in the database it comes empty, I need help to know where the problem is.
I have setup a riverpod provider in order to listen to a document in firestore as shown below.
My assumption was that the document is only read once after the start of the app and then only read / charged when the content has changed.
When I run the firestore emulator it shows me frequent GET calls against this object.
Is there a way to stream a single object without document reads or do I have to use a query snapshot for that?
final habitProvider =
StateNotifierProvider<ObjectRepository, AsyncValue<Object>>(
(ref) => ObjectRepository(ref.read));
class ObjectRepository extends StateNotifier<AsyncValue<Object>> {
final Reader _reader;
StreamSubscription<Object>? _subscription;
ObjectRepository(this._reader) : super(AsyncData(Object.empty())) {
state = const AsyncLoading();
try {
_subscription?.cancel();
_subscription = getObject().listen((event) {
state = AsyncData(event);
});
} catch (e) {
state = AsyncError(e);
}
}
Stream<HabitCollection> getObject() {
final docReference =
_reader(firebaseFirestoreProvider).collection("x").doc("y");
final snapshot = docReference.snapshots();
return snapshot.map((snapshot) {
if (snapshot.data() == null) {
return Object.empty();
} else {
return Object.fromJson(
snapshot.data() as Map<String, dynamic>);
}
});
}
void dispose() {
_subscription?.cancel();
super.dispose();
}
}
Hello I’m new to flutter
I’m trying to retrieve the user data from his email but i got this error [Null is not a subtype of type String]
The data I’m trying to retrieve is not null
This is my code
class _ProfilePageState extends State<ProfilePage> {
late User user;
final _auth = FirebaseAuth.instance;
late User signedInUser;
var id;
var email;
var name;
var age;
var sex;
#override
void initState() {
super.initState();
onRefresh(FirebaseAuth.instance.currentUser);
getCurrentUser();
}
onRefresh(userCare)
{
setState(()
{
user = userCare;
});
}
void getCurrentUser()
{
try {
final user = _auth.currentUser;
if (user != null) {
signedInUser = user;
email = signedInUser.email;
id = signedInUser.uid;
}
} catch (e) {
print(e);
}
}
void getData() {
FirebaseFirestore.instance
.collection('users')
.get()
.then((QuerySnapshot querySnapshot) {
querySnapshot.docs.forEach((doc) {
if (doc["email"] == signedInUser.email) {
name = doc['name'];
age = doc['age'];
sex = doc['sex'];
print(doc['name']);
}
});
});
}
This is my data
I want to retrieve then but i can’t because it says null how to fix the error?
this is the data I’m trying to retrieve
the error image
Please try this Code:
void getData() async {
await FirebaseFirestore.instance
.collection('users')
.get()
.then((value) {
for(var doc in value.docs) {
if (doc["email"] == signedInUser.email) {
name = doc.data()['name'];
age = doc.data()['age'];
sex = doc.data()['sex'];
print(doc.data()['name']);
}
}
});
}
So I have something like this which works fine with streamprovider.
Stream<List<AppUser>> streamUsers() {
return firestore.collection('users').snapshots().map(
(snapshot) => snapshot.docs
.map((document) => AppUser.fromJson(document.data()))
.toList(),
);
}
What I'm looking to achieve is something like this, where the stream will run in the background, and everytime data is transmitted it updates a local variable in my provider and notifies my widgets through provider that way. Is it bad idea? If so, why?
class AppUsers with ChangeNotifier {
FirebaseFirestore firestore = FirebaseFirestore.instance;
List<AppUser> _users;
List<AppUser> get users => _users;
void streamUsers() {
List<AppUser> users = [];
firestore
.collection('users')
.snapshots()
.map((snapshot) => snapshot.docs.map((document) {
AppUser user = AppUser.fromJson(document.data());
users.add(user);
}));
_users = users;
notifyListeners();
}
}
UPDATE
I was able to achieve this with the following code and calling init() when my app loads. I want to avoid calling init when my app loads tho. Is there a cleaner way?
List<AppUser> _users = [];
List<AppUser> get users => _users;
init() {
streamUsers().listen((event) {
_users = event;
notifyListeners();
});
}
Stream<List<AppUser>> streamUsers() {
return firestore.collection('users').snapshots().map(
(snapshot) => snapshot.docs
.map((document) => AppUser.fromJson(document.data()))
.toList(),
);
}
Remove the init function and use notify listener every stream event by mapping once more :
Stream<List<AppUser>> streamUsers() {
return firestore.collection('users').snapshots().map(
(snapshot) => snapshot.docs
.map((document) => AppUser.fromJson(document.data()))
.toList(),
).map((users) {
_users = users;
notifyListeners();
});
}
I am try to use a StreamProvider from a StateNotifierProvider.
Here is my StreamProvider, which works fine so far.
final productListStreamProvider = StreamProvider.autoDispose<List<ProductModel>>((ref) {
CollectionReference ref = FirebaseFirestore.instance.collection('products');
return ref.snapshots().map((snapshot) {
final list = snapshot.docs
.map((document) => ProductModel.fromSnapshot(document))
.toList();
return list;
});
});
Now I am trying to populate my shopping cart to have all the products in it from scratch.
final cartRiverpodProvider = StateNotifierProvider((ref) =>
new CartRiverpod(ref.watch(productListStreamProvider));
This is my CartRiverPod StateNotifier
class CartRiverpod extends StateNotifier<List<CartItemModel>> {
CartRiverpod([List<CartItemModel> products]) : super(products ?? []);
void add(ProductModel product) {
state = [...state, new CartItemModel(product:product)];
print ("added");
}
void remove(String id) {
state = state.where((product) => product.id != id).toList();
}
}
The simplest way to accomplish this is to accept a Reader as a parameter to your StateNotifier.
For example:
class CartRiverpod extends StateNotifier<List<CartItemModel>> {
CartRiverpod(this._read, [List<CartItemModel> products]) : super(products ?? []) {
// use _read anywhere in your StateNotifier to access any providers.
// e.g. _read(productListStreamProvider);
}
final Reader _read;
void add(ProductModel product) {
state = [...state, new CartItemModel(product: product)];
print("added");
}
void remove(String id) {
state = state.where((product) => product.id != id).toList();
}
}
final cartRiverpodProvider = StateNotifierProvider<CartRiverpod>((ref) => CartRiverpod(ref.read, []));