im getting this two errors in my debug console (core_booster, getBoosterConfig = false) and (Could not reach Firestore backend.) In my firestore data i ve got a Collection "Recipes" and then in de documents i ve got each recipe with its own attribute.
Here i leave you a sneek peek of the code.
new StreamBuilder(
stream: Firestore.instance.collection('Recipes').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData)
return const Center(child: CircularProgressIndicator());
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) =>
_buildListRecipe(context, snapshot.data.documents[index]),
);
});
Then in my _buildListRecipe I'm accessing each in the value of each recipe.
new Image.network(
document["firstImage"],
width: double.infinity,
height: 150.0,
fit: BoxFit.cover,
),
did you resolve your issue and do you remember how? I reach the exact same problem, I don't found any response or tips to resolve it.
Here, a bit of me code :
void _listenToUserDatabase(String key) async {
_userStream = _usersDatabase.child(key).onValue.listen((event) {
if (event.snapshot.value != null) {
final String source = jsonEncode(event.snapshot.value);
final Map<String, dynamic> json = jsonDecode(source);
_user = UserModel.fromJson(json, key: key);
_userKey = key;
notifyListeners();
}
}, onError: (e) {
print("Listen to user database error $e");
}, onDone: () {
print("listen done");
});
}
Related
I'm adding data from Firestore to a Stream from StreamBuilder, but I'm getting the following error:
Exception has occurred. StateError (Bad state: Snapshot has neither data nor error
My code.
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
AppState? estado;
static String? userID = FirebaseAuth.instance.currentUser?.uid;
static final userColeccion = FirebaseFirestore.instance.collection("users");
var groupfav = ' ';
Stream<QuerySnapshot>? taskGroup;
#override
void initState() {
super.initState();
getGroupFavData();
}
void getGroupFavData() async {
var groupFavData = await userColeccion.doc("$userID").get();
var groupfav = groupFavData.data()!['groupfav'];
taskGroup = FirebaseFirestore.instance
.collection("groups")
.doc(groupfav) // pass the obtained value
.collection("task")
.snapshots();
}
#override
Widget build(BuildContext context) {
estado = Provider.of<AppState>(context, listen: true);
return Scaffold(
appBar: AppBar(
title: const Text("Home"),
automaticallyImplyLeading: false,
),
body: StreamBuilder(
stream: taskGroup,
builder: (
BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot,
) {
if (snapshot.hasError) {
return const Text("error");
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text("Loading");
}
var data = snapshot.requireData;
return ListView.builder(
itemCount: data.size,
itemBuilder: (context, index) {
return Card(
child: ListTile(
title: Text("${data.docs[index]['titulo']}"),
subtitle: Text("${data.docs[index]['contenido']}"),
onTap: () {},
trailing: IconButton(
icon: const Icon(Icons.delete),
color: Colors.red[200],
onPressed: () {},
),
),
);
},
);
},
),
);
}
}
Ok, looking at your issue, I see that 1) you need to get the data of the document BEFORE you start listening on that document, which is normal, so you want to do a call first to the collection, get the document, then listen on the document's collection called task, which makes sense. Your issue is still an asynchronous issue. The app is rebuilding on a stream that still hasn't arrived; you have to fix the sequence of things.
You then need to switch things up a bit and do the following:
Option #1:
a) Use a FutureBuilder: this will allow you to make the async call to get the document name based on the user Id
b) After you get the document associated to that user, you want to listen on the stream produced by the collection called tasks in that document. There is where then you can hook up the StreamBuilder.
Option #2:
a) Keep things the way you have, but do a listen on the taskGroup snapshots; but keep rebuilding the list as the values arrive on that collection.
Those are my suggestions.
Here's some brief code on option 1:
// .. in your Scaffold's body:
Scaffold(
body: FutureBuilder( // the future builder fetches the initial data
future: userColeccion.doc("$userID").get(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasData) {
var groupfav = snapshot.data()!['groupfav'];
// then once the 'groupfav' has arrived,
// start listening on the taskGroup
taskGroup = FirebaseFirestore.instance
.collection("groups")
.doc(groupfav) // pass the obtained value
.collection("task")
.snapshots();
return StreamBuilder(
stream: taskGroup,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
// the rest of your code
});
}
return CircularProgressIndicator();
}
)
)
Option 2 would be something like:
List<Task> userTasks = [];
void getGroupFavData() async {
var groupFavData = await userColeccion.doc("$userID").get();
var groupfav = groupFavData.data()!['groupfav'];
taskGroup = FirebaseFirestore.instance
.collection("groups")
.doc(groupfav) // pass the obtained value
.collection("task")
.snapshots().listen((snapshot) {
// here populate a list of your tasks
// and trigger a widget rebuild once you've grabbed the values
// and display it as a list on the UI
setState(() {
userTasks = snapshot.docs.map((d) => Task.fromJson(d.data())).toList();
});
});
}
And in your Scaffold, you can have a ListView just rendering the items on that task list, like:
ListView.builder(
itemCount: userTasks.length,
itemBuilder: (context, index) {
// render your tasks here
})
Here's a Gist with some working code to illustrate my point. Run it on DartPad and you'll see how using a FutureBuilder wrapping a StreamBuilder will accomplish what you want.
If you run the above code on DartPad, you'll get the following output:
Hope those pointers take you somewhere.
I'm trying to retrieve all the courses that the user has enrolled in, these courses are present in an array within the document.
After retrieving the course ID from the users collection, I'm trying to retrieve the course details from the courses collection.
But before the courses variable is populated, the coursesCollection statement is executed and throwing the below error.
======== Exception caught by widgets library =======================================================
The following assertion was thrown building _BodyBuilder:
'in' filters require a non-empty [List].
'package:cloud_firestore/src/query.dart':
Failed assertion: line 706 pos 11: '(value as List).isNotEmpty'
Here is the error causing code:
List courses = [];
var coursesCollection;
void fetchCourses() async {
final loggedInUser = FirebaseAuth.instance.currentUser;
if (loggedInUser != null) {
final userCollection = await FirebaseFirestore.instance.collection('users').doc(loggedInUser.uid).get();
courses = userCollection.get('coursesEnrolled');
}
}
#override
void initState() {
fetchCourses();
coursesCollection = FirebaseFirestore.instance.collection('courses').where('courseID', whereIn: courses);
super.initState();
}
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: coursesCollection.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(backgroundColor: kBrandColor),
);
}
}
final courseListStream = snapshot.data!.docs.map((course) {
return CourseData.fromDocument(course);
}).toList();
List<BadgedCourseCard> courseCards = [];
for (var course in courseListStream) {
final courseDocID = course.courseDocID;
final courseID = course.courseID;
final courseTitle = course.courseTitle;
final courseImage = course.courseImage;
final courseBgColor = hexToColor(course.courseBackgroundColor.toString());
hexToColor(course.courseFgColor.toString());
final badgedCourseCard = BadgedCourseCard(
courseTitle: courseTitle.toString(),
courseTitleTextColor: courseFgColor,
cardBackgroundColor: courseBgColor,
courseImage: courseImage.toString(),
courseCardTapped: () {
Provider.of<CourseProvider>(context, listen: false).currentCourseDetails(
currentCourseDocID: courseDocID,
currentCourseID: courseID,
);
Navigator.of(context).push(ScaledAnimationPageRoute(CourseLandingPage(courseID: courseID.toString())));
},
courseBookmarkTapped: () => print("Course Bookmark Tapped"),
rightPadding: 3,
bottomPadding: 0.5,
cardWidth: 80,
);
courseCards.add(badgedCourseCard);
}
return SizedBox(
height: 20.5.h,
child: ListView(
physics: BouncingScrollPhysics(),
scrollDirection: Axis.horizontal,
children: courseCards,
),
);
},
);
}
How can I fix this issue?
Here,
coursesCollection = FirebaseFirestore.instance.collection('courses').where('courseID', whereIn: courses);
courses would be [] because fetchCourses is an async call.
Change the return type of fetchCourses from void to Future<void> & try using a then callback:
#override
void initState() {
super.initState();
fetchCourses().then((val) {
coursesCollection = FirebaseFirestore.instance.collection('courses').where('courseID', whereIn: courses);
setState(() {});
});
}
I would also recommend to use FutureBuilder as a better alternative.
coursesCollection is null that's why you're getting another error. Render StreamBuilder only when coursesCollection is not null.
coursesCollection != null ? StreamBuilder(...) : SizedBox(),
For listening to the user's enrolled courses, another StreamBuilder can be used. It would be a nested StreamBuilder setup.
StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance.collection('users').doc(FirebaseAuth.instance.currentUser.uid).snapshots(),
builder: (context, snapshot) => snapshot.hasData ? StreamBuilder<QuerySnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance.collection('courses').where('courseID', whereIn: snapshot.data!.data()!['coursesEnrolled']).snapshots(),
builder: (context, snapshotTwo) {},
) : Text('Loading...'),
),
Im struggling trying to use a streambuider. Im getting an error that says :
════════ Exception caught by widgets library ═══════════════════════════════════
The following _TypeError was thrown building StreamBuilder<UserData>(dirty, state: _StreamBuilderBaseState<UserData, AsyncSnapshot<UserData>>#e2c02):
type 'Future<QuerySnapshot>' is not a subtype of type 'Stream<dynamic>' of 'function result'
heres my code
Stream myVideos;
getalldata() async {
//get videos as future
myVideos = FirebaseFirestore.instance
.collection('videos')
.where('uid', isEqualTo: widget.userid)
.snapshots();
var documents = await FirebaseFirestore.instance
.collection('videos')
.where('uid', isEqualTo: widget.userid)
.get();
if (documents.docs.isNotEmpty) {
for (var item in documents.docs) {
likes = item.data()['likes'].length + likes;
}
} else {
setState(() {
picturesdontexists = true;
});
}
setState(() {
dataisthere = true;
});
}
#override
Widget build(BuildContext context) {
final user = Provider.of<Userforid>(context);
return dataisthere == false
? Scaffold(body: Center(child: CircularProgressIndicator()))
: StreamBuilder<UserData>(
stream: DatbaseService(uid: user?.uid).userData,
builder: (context, snapshot) {
if (snapshot.hasData) {
UserData userData = snapshot.data;
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0.0,
- - - - - - - - - -
),
),
StreamBuilder(
stream: myVideos,
builder: ( context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
if(videos>0){
print(snapshot.data);
return StaggeredGridView.countBuilder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
physics: ScrollPhysics(),
crossAxisCount: 3,
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index) {
DocumentSnapshot video =
snapshot.data.docs[index];
return InkWell(
onTap: () {
Navigator.of(context)
.pushNamed(ChatFirstpage.route);
},
child: Card(
elevation: 0.0,
What I think is that the error is thrown in the stream because before im using the stream myVideos im getting no error and all works fine .
Maye anyone can help Thank!. if you need more Information leave a comment .
Heres mine DatbaseService
class DatbaseService {
static DatbaseService instance = DatbaseService();
final String uid;
String _messages = "messages";
String _images = "images";
DatbaseService({this.uid});
//userData from snapshot
UserData userDataFromSnapshot(DocumentSnapshot snapshot) {
return UserData(
uid: uid,
email: snapshot.data()['email'],
fullname: snapshot.data()['fullname'],
password: snapshot.data()['password'],
url: snapshot.data()['url'],
username: snapshot.data()['username'],
);
}
//get user doc stream
Stream<UserData> get userData {
return myprofilsettings.doc(uid).snapshots().map(userDataFromSnapshot);
}
``
This usually arises when you are passing a Future where Stream should have gone or where you have defined the type of the variable as Stream but you are putting that variable equal to a future value.
I think instead of creating a variable like Stream myVideos you can directly put
FirebaseFirestore.instance
.collection('videos')
.where('uid', isEqualTo: widget.userid)
.snapshots()
inside the stream builder.
Also please provide the whole code (DatbaseService).
I am trying to query firebase with the following requirements:
If I have a location, I want to receive the data in a certain radius through the GeoFlutterfire plugin.
If I don't have a location, I want to receive data with a limit.
I don't know if I do it correctly, but I am having problems preparing the stream.
With firestore's .snapshot() method, I get a Stream<QuerySnapshot>, but with Geoflutterfire's collection(...).Within(...) method, I get a Stream <List <DocumentSnapshot>>. This gives me trouble when trying to display the data.
If anyone can clear my mind, I would be very grateful.
Thanks in advance.
Consumer<LocationProvider>(
builder: (_, location, __) {
if (location.loading) {
return Center(
child: CircularProgressIndicator(),
);
}
final ref =
FirebaseFirestore.instance.collection("publicaciones");
Stream<List<DocumentSnapshot>> stream;
final pos = location.direccion?.geoPoint;
if (pos != null) {
final geo = Geoflutterfire();
stream = geo.collection(collectionRef: ref).within(
center: geo.point(
latitude: pos.latitude,
longitude: pos.longitude,
),
field: "direccion.geoHash",
radius: radio,
);
}
return StreamBuilder(
stream: stream ?? ref.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
print(
"Error recibiendo publicaciones cercanas: ${snapshot.error}");
return Text("Error recibiendo publicaciones.");
}
if (snapshot.hasData) {
final List<Publicacion> publicaciones = snapshot.data
.map((p) => Publicacion.fromSnapshot(p))
.toList();
if (publicaciones.length == 0) {
return Text("No hay publicaciones cercanas.");
}
return ListView.builder(
shrinkWrap: true,
itemCount: publicaciones.length,
itemBuilder: (BuildContext context, int index) {
return Text(publicaciones[index].titulo);
},
);
}
return Center(
child: CircularProgressIndicator(),
);
},
);
},
)
PS: I know that stream: stream ?? ref.snapshots() is not the best way to program, but my head is a bit clouded today, sorry.
I don't know if the title of the post describes my problem, so if you can think of a better one, I'll change it.
SOLUTION:
Thanks to William Cardenas I have restructured my code as follows:
final ref =
FirebaseFirestore.instance.collection("publicaciones");
final pos = location.direccion?.geoPoint;
Stream<List<Publicacion>> stream;
if (pos != null) {
final geo = Geoflutterfire();
stream = geo
.collection(collectionRef: ref)
.within(
center: geo.point(
latitude: pos.latitude,
longitude: pos.longitude,
),
field: "direccion.geoHash",
radius: radio,
)
.map<List<Publicacion>>(
(snap) =>
snap.map((s) => Publicacion.fromSnapshot(s)).toList(),
);
} else {
stream = ref.snapshots().map<List<Publicacion>>((snap) =>
snap.docs.map((s) => Publicacion.fromSnapshot(s)).toList());
}
Then I used my stream:
return StreamBuilder<List<Publicacion>>(
stream: stream,
builder: (context, snapshot) {...
Map returns and iterable so we have to remember to add the "toList()" at the end.
With the Stream<List<DocumentSnapshots>> we could continue mapping the snapshots to a specific model class by the following:
stream.map((snapshot) {final data = snapshot.data();
return data != null ? Publicacion.fromSnapshot(data)
: null
}).toList();
And then try your streambuilder with something like this:
StreamBuilder<List<Publicacion>>(
stream: stream, builder: (context, snapshot) {
if(snapshot.hasData) { final pubs = snapshot.data;
final children = pubs.map((pub) =>
Text(pub.name)).toList();
return ListView(children: children);
} return Center(child: CircularProgressIndicator());
} if(snapshot.hasError){ return Center(child:
Text('Some error occurred'));
}return Center(child: CircularProgressIndicator());
)
In general do the data conversions before calling the streambuilder.
I found following issue. Then I understand it.
Flutter / FireStore: how to display an image from Firestore in Flutter?
File uploading is succeeding.
var imgUrl = await ref.getDownloadURL();
print(imgUrl.toString());
However I have following error.
It seems I'm doing same.
Unhandled Exception: PlatformException(Error -13010, FIRStorageErrorDomain, Object images/cars/40711b90-9db4-11ea-c602-a557c9b7697a.jpeg does not exist.)
However I have no idea how to display and handle it.
Please give me advice. Thanks.
You need to add the url to firestore first:
StorageTaskSnapshot snapshot = await storage
.ref()
.child("images/$imageName")
.putFile(file)
.onComplete;
if (snapshot.error == null) {
final String downloadUrl =
await snapshot.ref.getDownloadURL();
await Firestore.instance
.collection("images")
.add({"url": downloadUrl, "name": imageName});
}
Now in Firestore you will have collection called images and document with the image url and image name. The method getDownloadUrl() returns the url of the image so you can store it in Firestore. Then to display it you can do the following:
body: Container(
padding: EdgeInsets.all(10.0),
child: FutureBuilder(
future: getImages(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
shrinkWrap: true,
itemCount: snapshot.data.documents.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
contentPadding: EdgeInsets.all(8.0),
title:
Text(snapshot.data.documents[index].data["name"]),
leading: Image.network(
snapshot.data.documents[index].data["url"],
fit: BoxFit.fill),
);
});
} else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
}
return CircularProgressIndicator();
},
),
),
/// code here
Future<QuerySnapshot> getImages() {
return fb.collection("images").getDocuments();
}
Here you use the method getImages() which retrieves all the images from the collection images. To display the image you can use Image.network widget.