I'm trying to display my Data from Firestore in my Flutter Web App, but I don't get any data.
Basically I just adjusted this example: https://firebase.flutter.dev/docs/firestore/usage#realtime-changes
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class DataList extends StatefulWidget {
#override
_DataListState createState() => _DataListState();
}
class _DataListState extends State<DataList> {
#override
Widget build(BuildContext context) {
CollectionReference collectionReference = FirebaseFirestore.instance.collection('data');
return StreamBuilder<QuerySnapshot>(
stream: collectionReference.snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
print('HasData: ${snapshot.hasData}');
if (snapshot.hasError) {
print(snapshot.error);
return Text('Error: ${snapshot.error}');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return new ListView(
children: snapshot.data.docs.map((DocumentSnapshot document) {
return new ListTile(
title: new Text(document.data()['name']),
subtitle: new Text(document.data()['description']),
);
}).toList(),
);
},
);
}
}
But snapshot.hasData is always null and I get this error:
[cloud_firestore/unknown] NoSuchMethodError: invalid member on null: 'includeMetadataChanges'
Getting a single Document works fine:
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
class GetData extends StatelessWidget {
final String documentId;
GetData(this.documentId);
#override
Widget build(BuildContext context) {
CollectionReference collectionReference = FirebaseFirestore.instance.collection('data');
return FutureBuilder<DocumentSnapshot>(
future: collectionReference.doc(documentId).get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data = snapshot.data.data();
return Text("Name: ${data['name']}, Description: ${data['description']}");
}
return Text("loading");
},
);
}
}
What am I doing wrong?
I don't really need it to be Realtime, btw.
Try replacing your firestore script in index.html file with this:
<script src="https://www.gstatic.com/firebasejs/7.20.0/firebase-firestore.js"></script>
Related
I'm trying to work with realtime changes in firebase.
I found this doc but it only applies to collections. I'd like to grab data from a single document.
The sample code is below, how should I change it in order to refer to a document?
class UserInformation extends StatefulWidget {
#override
_UserInformationState createState() => _UserInformationState();
}
class _UserInformationState extends State<UserInformation> {
final Stream<QuerySnapshot> _usersStream =
FirebaseFirestore.instance.collection('users').snapshots();
#override
Widget build(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: _usersStream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text("Loading");
}
return ListView(
children: snapshot.data!.docs
.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return ListTile(
title: Text(data['full_name']),
subtitle: Text(data['company']),
);
})
.toList()
.cast(),
);
},
);
}
}
Maybe I found a solution, it seems working
StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore.instance.collection('Users').doc(documentId).snapshots(),
builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot<Map<String, dynamic>>> snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text("Loading");
}
Map<String, dynamic> data = snapshot.data!.data() as Map<String, dynamic>;
return Text(" Full name ${data['Full name']} ");
}
)
my main code:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:day_event_viewer/services/firestore.dart';
import 'package:flutter/material.dart';
class TodayEventScreen extends StatefulWidget {
#override
_TodayEventScreenState createState() => _TodayEventScreenState();
}
class _TodayEventScreenState extends State<TodayEventScreen> {
#override
Widget build(BuildContext context) {
return SafeArea(
child: StreamBuilder(
stream: getUserDatas(),
builder:
(BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return const Text('loading data');
} else if (snapshot.hasData) {
return ListView(
children: snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return ListTile(
title: Text(data['name']),
// subtitle: Text(data['company']),
);
}).toList(),
);
}
return const Text('somethng\'s wrong');
}),
);
}
}
the stream getUserDatas() mentioned above:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:day_event_viewer/screens/add_screen.dart';
Stream<QuerySnapshot> getUserDatas() async* {
final uid = await getUid();
yield* FirebaseFirestore.instance
.collection('usersdatas')
.doc(uid)
.collection('profile')
.where('date', isEqualTo: DateTime.now().day)
.snapshots();
}
when I comment the code ".where('date', isEqualTo: DateTime.now().day)" 'above 4 lines' it's working fine so i think maybe my querying is the problem but i don't know how to fix it.
try this
title: Text(document.get('name')),
you should put else keyword before this line.
return const Text('somethng\'s wrong');
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';
class ListStudentPage extends StatefulWidget {
State<StatefulWidget> createState() {
return _ListStudentPage();
}
}
class _ListStudentPage extends State<ListStudentPage> {
final Stream<DocumentSnapshot<Map<String, dynamic>>> productsStream =
FirebaseFirestore.instance
.collection('Categories')
.doc('Pharmacy')
.snapshots();
#override
Widget build(BuildContext context) {
return StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: productsStream,
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot<Map<String, dynamic>>> snapshot) {
if (snapshot.hasError) {
print('Something went Wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
final List productDocs = [];
snapshot.data!.docs.map((DocumentSnapshot document) {
Map a = document.data() as Map<String, dynamic>;
productDocs.add(a);
a['id'] = document.id;
}).toList();
});
}
}
I am getting this error "The getter 'docs' isn't defined for the type 'DocumentSnapshot<Map<String, dynamic>>" in the line right below( snapshot.data!.docs.map((DocumentSnapshot document,docs here is highlighted with a red underline)
) , where I created an empty list , can anyone please tell me why I am getting this error and how can I fix it .
Use QuerySnapshot<Map<String, dynamic>> , because its used when your getting a stream or a list which is the case for you now, while use DocumentSnapshot<Map<String, dynamic>> when your getting a single item.
Your productsStream refers to a single document named Pharmacy under the Category collection. Since you're reading only a single document, there is no need for the snapshot.data!.docs.map and you can just return a single widget for the one document you loaded.
Something like this for example:
return StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: productsStream,
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot<Map<String, dynamic>>> snapshot) {
if (snapshot.hasError) {
print('Something went Wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
return Text(snapshot.data!.get('id')); // 👈
});
I'm brand new to dart/flutter/firebase and having trouble figuring out how to get collection data from firestore. The following says an invalid collection path.
import 'package:flutter/material.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
class UserProfile extends StatelessWidget {
final String documentId = FirebaseAuth.instance.currentUser.uid;
#override
Widget build(BuildContext context) {
CollectionReference users = FirebaseFirestore.instance.collection("users");
return FutureBuilder<DocumentSnapshot>(
future: users.doc(documentId).get(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text("Something went wrong");
}
if (snapshot.hasData && !snapshot.data.exists) {
return Text("Document does not exist");
}
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data = snapshot.data.data();
return Text("Full Name: ${data['first_name']} ${data['last_name']}");
}
return Text("loading");
},
);
}
}
In this case it was incorrect firestore security rules, so this code is correct.
The Problem
Futurebuilder keeps returning "null" after the user has given permission to acces it's location so it can calculate the distance between 2 locations.
What I want it to do
It does give the location when the page is refreshed but I want the distance between 2 objects when the user gives acces to it's location, not when the user refreshed their page.
The Main Code to run the app
import 'package:flutter/material.dart';
import 'mainlist.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new MaterialApp(
routes: {
'/second': (context) => mainlist()
},
title: "testapp",
debugShowCheckedModeBanner: false,
home: mainlist(),
);
}
}
The code where the problem happens - Futurebuilder + getCurrenPosition Future
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:async/async.dart';
import 'package:geolocator/geolocator.dart';
import 'package:permission/permission.dart';
import 'mainlist.dart';
class mainlist extends StatefulWidget {
#override
_mainlistpage createState() => _mainlistpage();
}
class _mainlistpage extends State<mainlist> {
Future<String> getCurrentPosition(DocumentSnapshot document) async{
Position position = await Geolocator().getCurrentPosition(desiredAccuracy: LocationAccuracy.high);
double distanceInMeters = await Geolocator().distanceBetween(position.latitude, position.longitude, document['lat'], document['lat']);
return distanceInMeters.toString();
}
var sortBy = "";
Widget homePage() {
return StreamBuilder(
stream: Firestore.instance.collection("Test").orderBy(sortBy).snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return Text("Loading");
return ListView.builder(
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) =>
_mainListItem(context, snapshot.data.documents[index]));
},
);
}
#override
Widget _mainListItem(BuildContext context, DocumentSnapshot document) {
return Scaffold(
body: Container(
child: Center(
child: Column(
children: <Widget>[
FutureBuilder(
future: getCurrentPosition(document),
builder: (BuildContext context,AsyncSnapshot snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('none');
case ConnectionState.active:
case ConnectionState.waiting:
return Text('waiting');
case ConnectionState.done:
if (snapshot.hasError)
return Text('Error: ${snapshot.error}');
return Text(snapshot.data.toString());
}
return null; // unreachable
}
),
]
),
),
),
);
}
Widget build(BuildContext context){
return new Scaffold();
}
}
What have I tried
Using streambuilder
Messing with the cases in the Futurebuilder
Reading Stackoverflow
I have added the permissions in plist and manifest