Flutter snapshot.data() always null - flutter

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

How to retrieve real time changes from Firestore document in Flutter?

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']} ");
}
)

I'm getting a blank screen instead of firestore data

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');

The getter 'docs' isn't defined for the type 'DocumentSnapshot<Map<String, dynamic>>

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')); // 👈
});

How do I get a firestore collection document from a user 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.

FLUTTER - Futurebuilder keeps returning null after Location Permission

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