How to get specific fields from documentsnapshot - flutter

I have collection where i want to get fields. I have followed instructions on flutter fire and it says to use get() to retrieve documentsnapshot. I am creating a documentsnapshot object and trying to get all for a given id. Now i am trying to pass this stream into streambuilder and display specific fields. But i am getting error;
type '_BroadcastStream<DocumentSnapshot<Map<String, dynamic>>>' is not a subtype of
type
'Stream<QuerySnapshot<Object?>>?'
My code is;
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:quicktodo/model/authservice.dart';
class events extends StatefulWidget {
analytics({Key? key}) : super(key: key);
String uida = FirebaseAuth.instance.currentUser!.uid;
#override
_analyticsState createState() => _analyticsState();
}
class _ eventsState extends State<analytics> {
late final _stream;
String uid = FirebaseAuth.instance.currentUser!.uid;
void initState() {
super.initState();
setState(() {
_stream = FirebaseFirestore.instance.collection('events').doc(uid).get();
});
}
#override
Widget build(BuildContext context) {
final authService = Provider.of<AuthClass>(context);
return Scaffold(
appBar:AppBar(
leading:
IconButton(
icon: Icon(Icons.logout),
tooltip: 'List of your activities',
onPressed: () {
authService.signout(
);
},
),
title: const Text('Activity list'),
actions: <Widget>[
IconButton(
icon: const Icon(Icons.add),
tooltip: 'List of your activities',
onPressed: () {
},
),
],
),
body: StreamBuilder(
stream: _stream,
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
return ListView(
children: snapshot.data!.docs.map((DocumentSnapshot document) {
// final trip = DataModel.fromSnapshot(document);
Map a = document.data() as Map<String, dynamic>;
a['id'] = document.id;
return Container(
child: Text(a['eventone']),
);
}).toList(),
);
},
),
);
}
}

Replace your stream builder with this:
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('events')
.doc(uid)
.snapshots(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) return Text('Something went wrong');
if (snapshot.connectionState == ConnectionState.waiting)
return Text("Loading");
Map data = snapshot.data.data();
print(data['eventide']); // should print 4
print(data['eventtwo']); // should print 5
return SizedBox();
},
);
I changed your initial stream builder because it will only work for collection snapshot, not document snapshot.

Related

rebuilding listview.builder every time I scroll , and 'Stream has already been listened to' error

I am using a stream builder which has another stream builder inside it. Every time I get data from the first stream I use some of this data in the other stream to finally build a list view (POSTS), but I have a problem every time I scroll down I have this error:
if (!_isInitialState) {
throw StateError("Stream has already been listened to.");
}
I tried to listen to the second stream asBroadcastStream(), and I added the case that there is no data and every time I scroll I get the notification I made that there is no data any ideas?
This is my code:
StreamBuilder<QuerySnapshot>(
stream: posts.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
return SizedBox(
height: MediaQuery.of(context).size.height * 0.69,
child: ListView(
scrollDirection: Axis.vertical,
children:
snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return StreamBuilder<DocumentSnapshot>(
stream: users
.doc(data['Uid'])
.get()
.asStream()
.asBroadcastStream(),
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return const Text("Something went wrong");
}
if (snapshot.hasData && !snapshot.data!.exists) {}
if (!(snapshot.hasData)) {
print("no data");
return SizedBox(
width: 0,
);
}
if (snapshot.connectionState ==
ConnectionState.done) {
Map<String, dynamic> daata = snapshot.data!
.data() as Map<String, dynamic>;
String username = daata['Username'];
String userimage = daata['Userimage'];
return mypost(
context,
data['title'],
data['ImageUrl'],
data['context'],
username,
userimage,
data['nlikes'],
data['ncomments'],
data['date']
.toDate()
.toString()
.split(' ')
.first);
}
return const Text("loading");
});
}).toList(),
),
);
}),
if any could help I would be happy with that.
It might interest you to know that when I run the below code (basically your code, but with my streams and mypost() function) I don't get any errors!... It scrolls fine!
import 'package:firebase_core/firebase_core.dart';
import 'package:my_app/firebase_labels.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Screen(),
);
}
}
class MyFirebase {
static FirebaseFirestore storeObject = FirebaseFirestore.instance;
}
class Screen extends StatelessWidget {
Screen({Key? key}) : super(key: key);
// Let me just define some streams here, from the same CollectionReference:
final CollectionReference posts = MyFirebase.storeObject
.collection(kCollectionConversations);
final CollectionReference users = MyFirebase.storeObject
.collection(kCollectionConversations);
#override
Widget build(BuildContext context) {
return Scaffold(
body: StreamBuilder<QuerySnapshot>(
stream: posts.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
return SizedBox(
height: MediaQuery.of(context).size.height * 0.69,
child: ListView(
scrollDirection: Axis.vertical,
children:
snapshot.data!.docs.map((DocumentSnapshot document) {
Map<String, dynamic> data =
document.data()! as Map<String, dynamic>;
return StreamBuilder<DocumentSnapshot>(
stream: users
.doc(data['Uid'])
.get()
.asStream()
.asBroadcastStream(),
builder: (BuildContext context,
AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return const Text("Something went wrong");
}
if (snapshot.hasData && !snapshot.data!.exists) {}
if (!(snapshot.hasData)) {
print("no data");
return SizedBox(
width: 0,
);
}
if (snapshot.connectionState ==
ConnectionState.done) {
Map<String, dynamic>? daata = snapshot.data!
.data() as Map<String, dynamic>?;
String username = '';
String userimage = '';
if (daata != null) {
username = daata['Username'];
userimage = daata['Userimage'];
}
return mypost(
data,
// context,
data['title'],
data['ImageUrl'],
data['context'],
username,
userimage,
data['nlikes'],
data['ncomments'],
// data['date']
// .toDate()
// .toString()
// .split(' ')
// .first
);
}
return const Text("loading");
});
}
).toList(),
),
);
}),
);
}
}
Widget mypost(var data1, var data2, var data3, var data4, var data5, var data6, var data7, var data8/*, var data9,*/) {
return Container(
// height: 50,
child: Text('$data1'),
decoration: BoxDecoration(border: Border.all(color: Colors.blue)),
);
}
If you copy-paste this code into yours, do you get errors?
What if you change the streams for yours and the mypost() for yours? Do you get errors then?

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

Need help retrieving authorized user information Flutter Firestore

I have implemented in my flutter application Authentication via Firebase by login and password.
I also connected to a Firestore table with user data.
I only need to show the authenticated user's data by their ID, which are assigned to the other data tables.
How to link e.g. Users id: 1 with Tasks User id:1 ?
home_page.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:loginui/read_data/get_user_name.dart';
class MyTaskPage extends StatefulWidget {
const MyTaskPage({Key? key}) : super(key: key);
#override
State<MyTaskPage> createState() => _MyTaskPageState();
}
class _MyTaskPageState extends State<MyTaskPage> {
final user = FirebaseAuth.instance.currentUser!;
// document IDs
List<String> docIDs = [];
// get docIDs
Future getDocId() async {
await FirebaseFirestore.instance
.collection('tasks')
.orderBy('name', descending: true)
// .where('age', isGreaterThan: 44)
.get()
.then((snapshot) => snapshot.docs.forEach((document) {
print(document.reference);
docIDs.add(document.id);
}));
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.deepPurple[200],
centerTitle: true,
actions: [
GestureDetector(
onTap: () {
setState(() {
FirebaseAuth.instance.signOut();
});
},
child: Icon(Icons.logout),
),
],
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: FutureBuilder(
future: getDocId(),
builder: (context, snapshot) {
return ListView.builder(
itemCount: docIDs.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListTile(
title: GetUserName(documentId: docIDs[index]),
tileColor: Colors.grey[200],
),
);
},
);
},
),
),
],
),
),
);
}
}
get_user_name.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class GetUserName extends StatelessWidget {
final String documentId;
GetUserName({required this.documentId});
#override
Widget build(BuildContext context) {
// get the collection
CollectionReference users = FirebaseFirestore.instance.collection('tasks');
return FutureBuilder<DocumentSnapshot>(
future: users.doc(documentId).get(),
builder: ((context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
Map<String, dynamic> data =
snapshot.data!.data() as Map<String, dynamic>;
return Text(
'${data['name']}',
overflow: TextOverflow.ellipsis,
softWrap: true,
);
}
return Text('Loading...');
}),
);
}
}
final _auth = FirebaseAuth.instance;
final _firestore = FirebaseFirestore.instance;
if (_auth.currentUser != null) {
// user is signed in
final uid = _auth.currentUser!.uid;
final userData = await _firestore.collection('users').doc(uid).get();
final taskData = await _firestore.collection('tasks').doc(uid).get();
// handle the data
}

NoSuchMethodError (NoSuchMethodError: The method '[]' was called on null. Receiver: null Tried calling: [](0))

I am trying to create an application and this application gets information from the open-meteo API. I keep on encountering some errors that don't know how to fix. Would appreciate any help!!
title: Text(snapshot.data[i].longitude), //This is the line that is producing the error
import 'dart:convert';
import 'dart:ffi';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp(MaterialApp(
home: HomePage(),
debugShowCheckedModeBanner: false,
));
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Future getUserData() async {
var response = await http.get(Uri.parse( 'https://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&hourly=temperature_2m'));
var jsonData = jsonDecode(response.body);
List<User> users = [];
for (var u in (jsonData)) {
User user = User(u['longitude'], u['latitude'], u['hourly'], u['time'],u['temperature']);
users.add(user);
}
print(users.length);
return users;
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Rangers Tool'),
),
body: Container(
child: Card(
child: FutureBuilder(
future: getUserData(),
builder: (context, AsyncSnapshot snapshot) {
return ListView.builder(
itemCount: snapshot.data?.length,
itemBuilder: (context, i) {
return ListTile(
title: Text(snapshot.data[i].longitude),
subtitle: Text(snapshot.data[i].latitude),
);
});
}
},
))), ); } }
class User {
final String longitude, latitude, hourly, time, temperature;
User(this.longitude, this.latitude, this.hourly, this.time, this.temperature); }
}
You need to add a condition to make sure that data is there by checking the status of the snapshot before using it to build your list. Similar to this:
FutureBuilder(
future: _fetchListItems(),
builder:(context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
} else if (snapshot.hasError) {
SnapshotError(snapshot.error),
} else {
return ListView.builder(
itemCount: snapshot.data?.length,
itemBuilder: (context, i) {
return ListTile(
title: Text(snapshot.data[i].longitude),
subtitle: Text(snapshot.data[i].latitude),
);
}
}
)

I am failing to get data from cloud firestore while using flutter

At first, when i started writing my calls to get data from firestore, it worked. But when i tried writing more docs to my collection, it failed to bring data for the docs i recently added. Then, when i deleted the first one i added, i stopped receiveing data from firestore all together. I have tried several methods, but have all ended in failure.
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
class collect extends StatefulWidget {
#override
_collectState createState() => _collectState();
}
class _collectState extends State<collect>
{
Future _data;
void initState()
{
super.initState();
_data = getStuff();
}
Future getStuff()
async {
var firestore = FirebaseFirestore.instance;
QuerySnapshot qn = await firestore.collection("buses").get();
return qn.docs;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: _data,
builder: (_, snapshot)
{
if(snapshot.connectionState == ConnectionState.waiting)
{
return Center(
child:Text("Loading")
);
}
else if(snapshot.connectionState == ConnectionState.done)
{
return ListView.builder(itemCount: snapshot.data.length,itemBuilder:(_, index)
{
return Container(
child: ListTile(
title: Text(snapshot.data[index].data()["name"].toString()),
subtitle: Text(snapshot.data[index].data()["price"].toString()),
),
);
});
}
},
),
);
}
}
```![enter image description here](https://i.stack.imgur.com/L7FqF.jpg)
Define your database call as,
Future getStuff() async {
var docs;
await FirebaseFirestore.instance
.collection("buses")
.get()
.then((querySnapshot) {
docs = querySnapshot.docs;
});
return docs;
}
Then use the FutureBuilder in the build() function as,
return Scaffold(
body: Center(
child: FutureBuilder<dynamic>(
future: getStuff(),
builder: (BuildContext context, AsyncSnapshot<dynamic> snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (_, index) {
return Container(
child: ListTile(
title: Text(
snapshot.data[index].data()["name"].toString()),
subtitle: Text(
snapshot.data[index].data()["price"].toString()),
),
);
});
} else {
return CircularProgressIndicator();
}
},
),
),
);
I wrapped the FutureBuilder inside a Center just for clarity, you may remove that Center widget.