How to read List of Instance of '_JsonQuerySnapshot' in Flutter - flutter

I am trying to read the data from a list that has the data of Instance of '_JsonQuerySnapshot'.
In the below code I am trying to get the data from DB
getData() async {
var db = FirebaseFirestore.instance;
var categoryList = [];
db.collection('categories')
.doc(value)
.get()
.then((DocumentSnapshot doc) {
var listSubCol = doc["categoryCollection"];
listSubCol.forEach((id) {
db.collection('categories')
.doc(value)
.collection(id)
.get()
.then((snapshot) {
categoryList.add(snapshot);
return categoryList;
});
});
});
}
Below is the code where I am printing the values.
FutureBuilder(
future: getData(),
builder: (BuildContext context, snapshot){
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.connectionState == ConnectionState.done) {
print('Data: ${snapshot.data}');
return Text("Text");
}
return Text("Text Outside");
}
)
I got a null value.
Can anyone please help me with how to get the data?

The getData is a Future<void>, so when the FutureBuilder is completed the snapshot.data is always null.
Change getData to return a List of whatever you are getting.
Future<List<Categories>> getData() async {
var db = FirebaseFirestore.instance;
final List<Categories> categoryList = [];
await db.collection('categories')
.doc(value)
.get()
.then((DocumentSnapshot doc) {
var listSubCol = doc["categoryCollection"];
listSubCol.forEach((id) {
db.collection('categories')
.doc(value)
.collection(id)
.get()
.then((snapshot) {
categoryList.add(snapshot);
return categoryList;
});
});
});
return categoryList;
}

getData() async {
var db = FirebaseFirestore.instance;
await db.collection('categories').doc(value).get().then((DocumentSnapshot doc) {
var listSubCol = doc["categoryCollection"];
listSubCol.forEach((id) {
db.collection('categories').doc(value).collection(id).get().then((snapshot) {
snapshot.docs.forEach((element) {
categoryList.add(element.data());
});
});
return categoryList;
});
});
return categoryList;
}
using the above method i got the data from Firestore.

Related

Flutter - Null check operator used on a null value

I am trying to retrieve user data using a DocumentSnapshot. However I am getting a casterror because the instance that I created is pointing to null. So I tried calling the method getUserProfileData in the initState method to see if it could assign a value to my DocumentSnapshot instance but I still get that error. Please may anyone kindly help.
//DocumentSnapshot instance that is null
DocumentSnapshot? userDocument;
getUserProfileData() {
FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid)
.snapshots()
.listen((event) {
userDocument = event;
});
}
#override
void initState() {
getUserProfileData();
//This is where the castError occurs because userDocument is null
nameController.text = userDocument!.get('name');
userNameController.text = userDocument!.get('username');
try {
descriptionController.text = userDocument!.get('description');
} catch (e) {
descriptionController.text = '';
}
try {
followers = userDocument!.get('followers').length;
} catch (e) {
followers = 0;
}
try {
following = userDocument!.get('following').length;
} catch (e) {
following = 0;
}
}
It would be better to use StreamBuilder for firstore-snapshot.
late final stream = FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid)
.snapshots();
#override
Widget build(BuildContext context) {
return StreamBuilder(
stream: stream,
builder: (context, snapshot) {....},
);
}
Also error can be bypass like
getUserProfileData() {
FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid)
.snapshots()
.listen((event) {
userDocument = event;
/// all those stuff here
nameController.text = userDocument!.get('name');
userNameController.text = userDocument!.get('username');
..........
Try use async/await for getUserProfileData() function
getUserProfileData() async {
await FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid)
.snapshots()
.listen((event) {
userDocument = event;
});
}
#override
void initState() {
getUserProfileData();
// Replace with default value case userDocument is null
nameController.text = userDocument!.get('name') ?? "";
userNameController.text = userDocument!.get('username') ?? "";
try {
descriptionController.text = userDocument!.get('description') ?? "";
} catch (e) {
descriptionController.text = '';
}
try {
followers = userDocument!.get('followers').length ?? 0;
} catch (e) {
followers = 0;
}
try {
following = userDocument!.get('following').length ?? 0;
} catch (e) {
following = 0;
}
}
Async determines that a method will be asynchronous, that is, it will not return something immediately, so the application can continue executing other tasks while processing is not finished.
await serves to determine that the application must wait for a response from a function before continuing execution. This is very important because there are cases where a function depends on the return of another.
a ?? b means that if the value of a is null, the value b will be assigned

flutter type 'List<dynamic>' is not a subtype of type 'FutureOr<List<Product>>'

I got FutureBuilder snapshot error when I parsing my JSON i got the:
type 'List' is not a subtype of type 'FutureOr<List>'
is it my Product model error or a parsing error?
my code
late Future<List<Product>> productFuture = getProducts();
static Future<List<Product>> getProducts() async {
var url = '${Constants.API_URL_DOMAIN}action=catalog&category_id=$id';
final response = await http.get(Uri.parse(url));
final body = jsonDecode(response.body);
print(body['data']);
return body['data'].map((e)=>Product.fromJson(e)).toList();
}
FutureBuilder<List<Product>>(
future: productFuture,
builder: (context, snapshot) {
print(snapshot);
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasData) {
final catalog = snapshot.data;
return buildCatalog(catalog!);
} else {
print('SNAPSOT DATA ${snapshot.data}');
return Text("No widget to build");
}
}),
Use List.from
return List.from(body['data'].map((e)=>Product.fromJson(e)));
static Future<List<Product>> getProducts() async {
var url = '${Constants.API_URL_DOMAIN}action=catalog&category_id=$id';
final response = await http.get(Uri.parse(url));
final body = jsonDecode(response.body);
print(body['data']);
return List.from(body['data'].map((e)=>Product.fromJson(e)));
}
Try to convert all List<Product> --> List<dynamic>

Pagination for Flutter ListView.builder [duplicate]

I'm trying to paginate by using Firestore and I read the document and it implement like this in Swift
let first = db.collection("cities")
.order(by: "population")
.limit(to: 25)
first.addSnapshotListener { (snapshot, error) in
guard let snapshot = snapshot else {
print("Error retrieving cities: \(error.debugDescription)")
return
}
guard let lastSnapshot = snapshot.documents.last else {
// The collection is empty.
return
}
// Construct a new query starting after this document,
// retrieving the next 25 cities.
let next = db.collection("cities")
.order(by: "population")
.start(afterDocument: lastSnapshot)
// Use the query for pagination.
// ...
}
Just for practice, I tried fetched three documents and if button tapped, fetch one more document.
Firestore.instance.collection('user').where('name', isEqualTo: 'Tom').orderBy('age').limit(3).getDocuments().then((snapshot) {
_lastDocument = snapshot.documents.last;
snapshot.documents.forEach((snap) {
print(snap.data);
});
});
After button tapped tried like this.
Firestore.instance.collection('user').where('name', isEqualTo: 'Tom').orderBy('age').startAfter(_lastDocument).limit(1).getDocuments().then((snapshot) {
snapshot.documents.forEach((snap) {
print(snap.data);
});
});
But console says this.
The following assertion was thrown while handling a gesture: type
'DocumentSnapshot' is not a subtype of type 'List[dynamic]'
Why do I have to pass list?
Does anyone know how to fix this?
UPDATE
I was able to paginate like so.
class PaginationExample extends StatefulWidget {
#override
_PaginationExampleState createState() => _PaginationExampleState();
}
class _PaginationExampleState extends State<PaginationExample> {
var _restaurants = <Restaurant>[];
var _nomore = false;
var _isFetching = false;
DocumentSnapshot _lastDocument;
ScrollController _controller;
void _fetchDocuments() async {
final QuerySnapshot querySnapshot = await Firestore.instance.collection('restaurants').orderBy('likes').limit(8).getDocuments();
// your logic here
}
Future<Null> _fetchFromLast() async {
final QuerySnapshot querySnapshot = await Firestore.instance.collection('restaurants').orderBy('likes').startAfter([_lastDocument['likes']]).limit(4).getDocuments();
if (querySnapshot.documents.length < 4) {
_nomore = true;
return;
}
_lastDocument = querySnapshot.documents.last;
for (final DocumentSnapshot snapshot in querySnapshot.documents) {
final Restaurant re = Restaurant(snapshot);
_restaurants.add(re);
}
setState(() {});
}
void _scrollListener() async {
if (_nomore) return;
if (_controller.position.pixels == _controller.position.maxScrollExtent && _isFetching == false) {
_isFetching = true;
await _fetchFromLast();
_isFetching = false;
}
}
#override
void initState() {
_fetchDocuments();
_controller = new ScrollController()..addListener(_scrollListener);
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
);
}
}
There is an error here:
Firestore.instance.collection('user').where('name', isEqualTo: 'Tom').orderBy('age').startAfter(_lastDocument).limit(1).getDocuments().then((snapshot) {
snapshot.documents.forEach((snap) {
print(snap.data);
});
});
startAfter method expects a List value params and you are passing a DocumentSnapshot.
Takes a list of [values], creates and returns a new [Query] that
starts after the provided fields relative to the order of the query.
You could try something like this:
Firestore.instance.collection('user').where('name', isEqualTo: 'Tom').orderBy('age').startAfter([{'name': 'Tom'}]).limit(1).getDocuments().then((snapshot) {
snapshot.documents.forEach((snap) {
print(snap.data);
});
});
Paginate just with 2 attrubutes, itemBuilder and query using this package - paginate_firestore
For example,
PaginateFirestore(
itemBuilder: (context, documentSnapshot) => ListTile(
leading: CircleAvatar(child: Icon(Icons.person)),
title: Text(documentSnapshot.data['name']),
subtitle: Text(documentSnapshot.documentID),
),
// orderBy is compulsary to enable pagination
query: Firestore.instance.collection('users').orderBy('name'),
)
This works for me giving realtime pagination
defining functions to fetch data
import 'package:cloud_firestore/cloud_firestore.dart';
import '../../../core/constants/firebase_constants.dart';
class FirebaseProvider {
final FirebaseFirestore _firestore;
FirebaseProvider({required FirebaseFirestore firestore})
: _firestore = firestore;
CollectionReference get _posts =>
_firestore.collection(FirebaseConstants.postsCollection);
Future<List<DocumentSnapshot>> fetchFirstList(
String fromgst, String postType) async {
return (await _posts
.where("fromgst", isEqualTo: fromgst)
.where("postType", isEqualTo: postType)
.orderBy("date", descending: true)
.limit(5)
.get())
.docs;
}
Future<List<DocumentSnapshot>> fetchNextList(String fromgst, String postType,
List<DocumentSnapshot> documentList) async {
return (await _posts
.where("fromgst", isEqualTo: fromgst)
.where("postType", isEqualTo: postType)
.orderBy("date", descending: true)
.startAfterDocument(documentList[documentList.length - 1])
.limit(5)
.get())
.docs;
}
}
separate class to handle pagination
import 'dart:async';
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:growmore/features/home/repository/firebase_provider.dart';
import 'package:rxdart/rxdart.dart';
class PostListBloc {
List<DocumentSnapshot>? documentList;
bool showIndicator = false;
FirebaseProvider? firebaseProvider;
BehaviorSubject<List<DocumentSnapshot>>? postController;
BehaviorSubject<bool>? showIndicatorController;
PostListBloc() {
postController = BehaviorSubject<List<DocumentSnapshot>>();
showIndicatorController = BehaviorSubject<bool>();
firebaseProvider = FirebaseProvider(firestore: FirebaseFirestore.instance);
}
Stream get getShowIndicatorStream => showIndicatorController!.stream;
Stream<List<DocumentSnapshot>> get postStream => postController!.stream;
// This method will automatically fetch first 10 elements from the document list
Future fetchFirstList(String fromgst, String postType) async {
try {
documentList = await firebaseProvider?.fetchFirstList(fromgst, postType);
print("documentList$documentList");
postController?.sink.add(documentList!);
try {
if (documentList!.isEmpty) {
postController?.sink.addError("No Data Available");
}
} catch (e) {
print(e);
}
} on SocketException {
postController?.sink.addError(SocketException("No Internet Connection"));
} catch (e) {
print(e.toString());
postController?.sink.addError(e);
}
}
//This will automatically fetch the next 10 elements from the list
fetchNextPosts(String fromgst, String postType) async {
try {
updateIndicator(true);
List<DocumentSnapshot> newDocumentList = await firebaseProvider!
.fetchNextList(fromgst, postType, documentList!);
print('asca$newDocumentList');
documentList!.addAll(newDocumentList);
postController!.sink.add(documentList!);
try {
if (documentList!.isEmpty) {
postController!.sink.addError("No Data Available");
updateIndicator(false);
}
} catch (e) {
updateIndicator(false);
}
} on SocketException {
postController!.sink.addError(SocketException("No Internet Connection"));
updateIndicator(false);
} catch (e) {
updateIndicator(false);
print(e.toString());
postController!.sink.addError(e);
}
}
//For updating the indicator below every list and paginate*
updateIndicator(bool value) async {
showIndicator = value;
showIndicatorController!.sink.add(value);
}
void dispose() {
postController!.close();
showIndicatorController!.close();
}
}
the ui part
ScrollController controller = ScrollController();
#override
void initState() {
super.initState();
postListBloc = PostListBloc();
print("dvvfe${widget.fromgst}");
postListBloc!.fetchFirstList(widget.fromgst, widget.postType);
controller.addListener(_scrollListener);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<List<DocumentSnapshot>>(
stream: postListBloc!.postStream,
builder: (context, snapshot) {
if (snapshot.data != null) {
return ListView.builder(
itemCount: snapshot.data?.length,
shrinkWrap: true,
controller: controller,
itemBuilder: (context, index) {
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ListTile(
title: Text(snapshot.data![index]['description']),
),
),
);
},
);
} else {
return const CircularProgressIndicator();
}
},
),
);
}
void _scrollListener() {
if (controller.offset >= controller.position.maxScrollExtent &&
!controller.position.outOfRange) {
print("Cavc$controller");
print("at the end of list");
postListBloc!.fetchNextPosts(widget.fromgst, widget.postType);
}
}
}
I found it not open source github repo

flutter I want to get List<int> values ​as ints one by one

I want to get List values ​​as ints one by one.
where movieId requires an int value.
help me please
thank you
Future<MovieDetailModel> getMovieDetail(int? movieId) async {
try {
http.Response res = await http
.get(Uri.parse('$mainUrl/movie/$**movieId**?$apiKey&language=ko-KR'))
.timeout(Duration(seconds: 8),
onTimeout: () async => new http.Response('{}', 404));
if (res.statusCode == 404) {
return MovieDetailModel.fromJson({});
}
Map<String, dynamic> result = jsonDecode(res.body);
MovieDetailModel movies = MovieDetailModel.fromJson(result);
return movies;
} catch (e) {
print('MovieDetail $e');
}
return MovieDetailModel.fromJson({});
}
where user.userMovieId value is List .
Widget userMovie(UserModel user) {
return FutureBuilder(
future: this._movieDetailProvider.movies(**user.userMovieId!**),
builder:
(BuildContext context, AsyncSnapshot<MovieDetailModel> snapshot) {
if (snapshot.hasData) {}
Provider.
Future<MovieDetailModel> movies(int movieId) async {
MovieDetailModel movieList = await _movieRepo.getMovieDetail(movieId);
notifyListeners();
return movieList;
}

Flutter Firestore pagination

I'm trying to paginate by using Firestore and I read the document and it implement like this in Swift
let first = db.collection("cities")
.order(by: "population")
.limit(to: 25)
first.addSnapshotListener { (snapshot, error) in
guard let snapshot = snapshot else {
print("Error retrieving cities: \(error.debugDescription)")
return
}
guard let lastSnapshot = snapshot.documents.last else {
// The collection is empty.
return
}
// Construct a new query starting after this document,
// retrieving the next 25 cities.
let next = db.collection("cities")
.order(by: "population")
.start(afterDocument: lastSnapshot)
// Use the query for pagination.
// ...
}
Just for practice, I tried fetched three documents and if button tapped, fetch one more document.
Firestore.instance.collection('user').where('name', isEqualTo: 'Tom').orderBy('age').limit(3).getDocuments().then((snapshot) {
_lastDocument = snapshot.documents.last;
snapshot.documents.forEach((snap) {
print(snap.data);
});
});
After button tapped tried like this.
Firestore.instance.collection('user').where('name', isEqualTo: 'Tom').orderBy('age').startAfter(_lastDocument).limit(1).getDocuments().then((snapshot) {
snapshot.documents.forEach((snap) {
print(snap.data);
});
});
But console says this.
The following assertion was thrown while handling a gesture: type
'DocumentSnapshot' is not a subtype of type 'List[dynamic]'
Why do I have to pass list?
Does anyone know how to fix this?
UPDATE
I was able to paginate like so.
class PaginationExample extends StatefulWidget {
#override
_PaginationExampleState createState() => _PaginationExampleState();
}
class _PaginationExampleState extends State<PaginationExample> {
var _restaurants = <Restaurant>[];
var _nomore = false;
var _isFetching = false;
DocumentSnapshot _lastDocument;
ScrollController _controller;
void _fetchDocuments() async {
final QuerySnapshot querySnapshot = await Firestore.instance.collection('restaurants').orderBy('likes').limit(8).getDocuments();
// your logic here
}
Future<Null> _fetchFromLast() async {
final QuerySnapshot querySnapshot = await Firestore.instance.collection('restaurants').orderBy('likes').startAfter([_lastDocument['likes']]).limit(4).getDocuments();
if (querySnapshot.documents.length < 4) {
_nomore = true;
return;
}
_lastDocument = querySnapshot.documents.last;
for (final DocumentSnapshot snapshot in querySnapshot.documents) {
final Restaurant re = Restaurant(snapshot);
_restaurants.add(re);
}
setState(() {});
}
void _scrollListener() async {
if (_nomore) return;
if (_controller.position.pixels == _controller.position.maxScrollExtent && _isFetching == false) {
_isFetching = true;
await _fetchFromLast();
_isFetching = false;
}
}
#override
void initState() {
_fetchDocuments();
_controller = new ScrollController()..addListener(_scrollListener);
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
);
}
}
There is an error here:
Firestore.instance.collection('user').where('name', isEqualTo: 'Tom').orderBy('age').startAfter(_lastDocument).limit(1).getDocuments().then((snapshot) {
snapshot.documents.forEach((snap) {
print(snap.data);
});
});
startAfter method expects a List value params and you are passing a DocumentSnapshot.
Takes a list of [values], creates and returns a new [Query] that
starts after the provided fields relative to the order of the query.
You could try something like this:
Firestore.instance.collection('user').where('name', isEqualTo: 'Tom').orderBy('age').startAfter([{'name': 'Tom'}]).limit(1).getDocuments().then((snapshot) {
snapshot.documents.forEach((snap) {
print(snap.data);
});
});
Paginate just with 2 attrubutes, itemBuilder and query using this package - paginate_firestore
For example,
PaginateFirestore(
itemBuilder: (context, documentSnapshot) => ListTile(
leading: CircleAvatar(child: Icon(Icons.person)),
title: Text(documentSnapshot.data['name']),
subtitle: Text(documentSnapshot.documentID),
),
// orderBy is compulsary to enable pagination
query: Firestore.instance.collection('users').orderBy('name'),
)
This works for me giving realtime pagination
defining functions to fetch data
import 'package:cloud_firestore/cloud_firestore.dart';
import '../../../core/constants/firebase_constants.dart';
class FirebaseProvider {
final FirebaseFirestore _firestore;
FirebaseProvider({required FirebaseFirestore firestore})
: _firestore = firestore;
CollectionReference get _posts =>
_firestore.collection(FirebaseConstants.postsCollection);
Future<List<DocumentSnapshot>> fetchFirstList(
String fromgst, String postType) async {
return (await _posts
.where("fromgst", isEqualTo: fromgst)
.where("postType", isEqualTo: postType)
.orderBy("date", descending: true)
.limit(5)
.get())
.docs;
}
Future<List<DocumentSnapshot>> fetchNextList(String fromgst, String postType,
List<DocumentSnapshot> documentList) async {
return (await _posts
.where("fromgst", isEqualTo: fromgst)
.where("postType", isEqualTo: postType)
.orderBy("date", descending: true)
.startAfterDocument(documentList[documentList.length - 1])
.limit(5)
.get())
.docs;
}
}
separate class to handle pagination
import 'dart:async';
import 'dart:io';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:growmore/features/home/repository/firebase_provider.dart';
import 'package:rxdart/rxdart.dart';
class PostListBloc {
List<DocumentSnapshot>? documentList;
bool showIndicator = false;
FirebaseProvider? firebaseProvider;
BehaviorSubject<List<DocumentSnapshot>>? postController;
BehaviorSubject<bool>? showIndicatorController;
PostListBloc() {
postController = BehaviorSubject<List<DocumentSnapshot>>();
showIndicatorController = BehaviorSubject<bool>();
firebaseProvider = FirebaseProvider(firestore: FirebaseFirestore.instance);
}
Stream get getShowIndicatorStream => showIndicatorController!.stream;
Stream<List<DocumentSnapshot>> get postStream => postController!.stream;
// This method will automatically fetch first 10 elements from the document list
Future fetchFirstList(String fromgst, String postType) async {
try {
documentList = await firebaseProvider?.fetchFirstList(fromgst, postType);
print("documentList$documentList");
postController?.sink.add(documentList!);
try {
if (documentList!.isEmpty) {
postController?.sink.addError("No Data Available");
}
} catch (e) {
print(e);
}
} on SocketException {
postController?.sink.addError(SocketException("No Internet Connection"));
} catch (e) {
print(e.toString());
postController?.sink.addError(e);
}
}
//This will automatically fetch the next 10 elements from the list
fetchNextPosts(String fromgst, String postType) async {
try {
updateIndicator(true);
List<DocumentSnapshot> newDocumentList = await firebaseProvider!
.fetchNextList(fromgst, postType, documentList!);
print('asca$newDocumentList');
documentList!.addAll(newDocumentList);
postController!.sink.add(documentList!);
try {
if (documentList!.isEmpty) {
postController!.sink.addError("No Data Available");
updateIndicator(false);
}
} catch (e) {
updateIndicator(false);
}
} on SocketException {
postController!.sink.addError(SocketException("No Internet Connection"));
updateIndicator(false);
} catch (e) {
updateIndicator(false);
print(e.toString());
postController!.sink.addError(e);
}
}
//For updating the indicator below every list and paginate*
updateIndicator(bool value) async {
showIndicator = value;
showIndicatorController!.sink.add(value);
}
void dispose() {
postController!.close();
showIndicatorController!.close();
}
}
the ui part
ScrollController controller = ScrollController();
#override
void initState() {
super.initState();
postListBloc = PostListBloc();
print("dvvfe${widget.fromgst}");
postListBloc!.fetchFirstList(widget.fromgst, widget.postType);
controller.addListener(_scrollListener);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<List<DocumentSnapshot>>(
stream: postListBloc!.postStream,
builder: (context, snapshot) {
if (snapshot.data != null) {
return ListView.builder(
itemCount: snapshot.data?.length,
shrinkWrap: true,
controller: controller,
itemBuilder: (context, index) {
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: ListTile(
title: Text(snapshot.data![index]['description']),
),
),
);
},
);
} else {
return const CircularProgressIndicator();
}
},
),
);
}
void _scrollListener() {
if (controller.offset >= controller.position.maxScrollExtent &&
!controller.position.outOfRange) {
print("Cavc$controller");
print("at the end of list");
postListBloc!.fetchNextPosts(widget.fromgst, widget.postType);
}
}
}
I found it not open source github repo