FirebaseFirestore firestore = FirebaseFirestore.instance;
List dataListWidget(AsyncSnapshot snapshot) {
return snapshot.data.docs[0].map((document) {
return ListTile(
title: Text(document["Name"]),
subtitle: Text(document["City"]),
);
}).toList();
}
//my streamBuilder
StreamBuilder(
stream: firestore.collection('customers').snapshots(),
builder: (context, snapshot) {
return ListView(
children: dataListWidget(snapshot),
);
},
),`
The query which you just fired returns empty mean it doesn't have any response in it and without checking any condition you are trying to access its 0th element.
You should do something like this
StreamBuilder(
stream:firestore.collection('customers').snapshots(),
builder:(context,snapshot){
if(snapshot.hasData && !snapshot.hasError){
return ListView(children: dataListWidget(snapshot),);
}
return Container();
});
And your dataListWidget should Look like this
List dataListWidget(AsyncSnapshot snapshot){
if(snapshot.data.docs.isNotEmpty){
return snapshot.data.docs[0].map((document) {
return ListTile(
title: Text(document["Name"]), subtitle: Text(document["City"]),
);
}).toList();
}
else{
return [Container()];
}
}
Related
Widget build(context) {
return Scaffold(
appBar: header(context, isApp: true, titleText: 'Instagram'),
body: StreamBuilder<QuerySnapshot>(
stream: userRef.snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
circularProgress();
}
final List<Text> list = snapshot.data!.docs
.map((user) => Text(user['username']))
.toList();
return Container(
child: ListView(
children: list,
),
);
},
),
);
}
The error message appears to be referring to the null check operator in this line
final List<Text> list = snapshot.data!.docs
.map((user) => Text(user['username']))
.toList();
implying that snapshot.data is null at this point.
Clearly you don't intend for this code to be executed if no data has been returned.
Since this block of code
if (!snapshot.hasData) {
circularProgress();
}
has no return statement, execution continues down the block.
Changing it to
if (!snapshot.hasData) {
return circularProgress();
}
should solve your problem
final String apiUrl = 'https://api.covid19api.com/summary';
Future globaldata() async{
var res = await http.get(Uri.parse(apiUrl));
Map s = await jsonDecode(res.body);
return s['Global']['NewConfirmed'];
}
//....
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("global cases"),
centerTitle: true,
),
body:Container(
child: FutureBuilder(
future: globaldata(),
builder: (context, snapshot){
if(snapshot.data != null){
print(globaldata());
return Text(globaldata().toString());
}else{
return Text("loading ...");
}
},
),
),
);
}
}
I am getting error of Instance of 'future'
Try doing these
child: FutureBuilder(
future: globaldata(),
builder: (context, snapshot) {
if(snapshot.data != null){
print(snapshot.data);
return Text(snapshot.data);
}else{
return Text("loading ...");
}
},
),
),
);
Check Print and return Text statement
You get this error because you are printing and returning Futures without await:
print(globaldata());
return Text(globaldata().toString());
Your FutureBuilder provides you the values you are trying to access in snapshot:
print(snapshot.data);
return Text(snapshot.data.toString());
Change your function to this.
Future globaldata() async {
http.Response response = await http.get(Uri.parse(apiUrl));
if (response.statusCode == 200) {
return jsonDecode(response.body)['Global']['NewConfirmed'];
} else {
throw Exception('Failed to load post');
}
}
and change your body to this.
body: FutureBuilder(
future: globaldata(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Center(
child: Text(snapshot.data.toString()),
);
} else if (snapshot.hasError) {
return Center(
child: Text("${snapshot.error}"),
);
}
return const Center(
child: CircularProgressIndicator(),
);
},
),
This works perfectly.
In my main.dart I have an async function to get data from an URL.
getShopLength() async {
final queryParameters = {
'api_key': '123',
'user_id': '123',
'lat': '123',
'long': '123',
'km': '123',
};
var response = await http.get(Uri.https('google.de','getSth', queryParameters));
var jsonData = jsonDecode(response.body);
List<Shops> shops = [];
for(var x in jsonData) {
Shops shop = Shops(x['name'], x['slogan']);
shops.add(shop);
}
return shops.length;
}
In my home.dart I want to get the value from getShopLength() but I always get the error: type 'Future<dynamic> is not a subtype of type 'Future<String>?'
I try to save the return value into valueShop and pass it to buildRestaurantRow('Top Angebote', context, valueShop)
home.dart
#override
Widget build(BuildContext context) {
var valueShop = "0";
FutureBuilder<String>(
future: getShopLength(),
builder: (context, snapshot) {
if (snapshot.hasData) {
valueShop = snapshot.data;
}
return CircularProgressIndicator();
}
);
return Scaffold(
appBar: buildSearchBar(context),
body: Padding(
padding: const EdgeInsets.fromLTRB(10.0, 0, 10.0, 0),
child: ListView(
children: <Widget>[
SizedBox(height: 20.0),
buildRestaurantRow('Top Angebote', context, valueShop),
SizedBox(height: 10.0),
buildRestaurantList(context),
SizedBox(height: 10.0),
buildCategoryRow('Nach Kategorie', context),
SizedBox(height: 10.0),
buildCategoryList(context),
SizedBox(height: 20.0),
buildCategoryRow('Deine Favoriten', context),
SizedBox(height: 10.0),
buildFriendsList(),
SizedBox(height: 30.0),
],
),
),
);
}
What am I missing?
So the problem lies here:
FutureBuilder<String>(
future: getShopLength(),
Your future builder has a type of string, which means that the future should be of type Future<String>, but when you declared the function getShopLength, you did this:
getShopLength() async {
You did not give it a return type, because of that, the default return type is Future<dynamic>.
The obvious solution is giving the function a return type, but you have another problem:
The futurebuilder expects a string value, but the function returns a number, so which is it?
If you want to return a string of the length, you can just do this:
Future<String> getShopLength() async {
...
return shops.length.toString();
}
Or you can also change the futurebuilder's value to be int:
Future<int> getShopLength() async {
...
return shops.length;
}
...
int valueShop = 0;
FutureBuilder<int>(
future: getShopLength(),
builder: (context, snapshot) {
if (snapshot.hasData) {
valueShop = snapshot.data;
}
return CircularProgressIndicator();
},
);
Side note:
Ok, I have a couple of things to mention about your code:
First of all, on your getShopsLength function, you have two lists, jsonData and shops, you don't actually need both, you can just use one:
var jsonData = jsonDecode(response.body);
return jsonData.length // no need for the shops list.
Second of all, what's up with your builder code?? You first declare a FutureBuilder, but then completely ignore it and move on to a Scaffold widget? I believe the scaffold code should be inside the future builder, as it stands, you will never see the circular progress indicator:
From:
var valueShop = '0';
FutureBuilder<String>(
future: getShopLength(),
builder: (context, snapshot) {
if (snapshot.hasData) {
valueShop = snapshot.data;
}
return CircularProgressIndicator();
}
);
return Scaffold(...);
To:
return FutureBuilder<String>(
future: getShopLength(),
builder: (context, snapshot) {
if (snapshot.hasData) {
var valueShop = snapshot.data;
return Scaffold(...);
}
return CircularProgressIndicator();
}
);
I want to check if my user is an admin and display a widget depending on that. My data is stored in Firestore such that there is a document in a 'users' collection with a user ID that contains an 'isAdmin' field. My current code looks like this:
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
FutureBuilder(
future: FirebaseAuth.instance.currentUser(),
builder: (ctx, futureSnapshot) {
if (futureSnapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
final uid = futureSnapshot.data.uid;
return StreamBuilder(
stream: Firestore.instance
.collection('users')
.document(uid)
.snapshots(),
builder: (ctx, userSnapshot) {
if (userSnapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
var userDocument = userSnapshot.data;
if (userDocument['isAdmin'] == true) {
return FloatingActionButton(
onPressed: () {},
);
}
},
);
},
),
],
),
),
);
}
However, this code runs and gives me an error that my build function returned null. How can I check if my current user is an admin if that data is stored in Firestore
Update your code to this
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: [
FutureBuilder(
future: FirebaseAuth.instance.currentUser(),
builder: (ctx, futureSnapshot) {
if (futureSnapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
final uid = futureSnapshot.data.uid;
return StreamBuilder(
stream: Firestore.instance
.collection('users')
.document(uid)
.snapshots(),
builder: (ctx, userSnapshot) {
if (userSnapshot.connectionState ==
ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
}
var userDocument = userSnapshot.data.data();
if (userDocument['isAdmin'] == true) {
return FloatingActionButton(
onPressed: () {},
);
}
},
);
},
),
],
),
),
);
}
Change 'var userDocument = userSnapshot.data;' to var userDocument = userSnapshot.data.data();
My Goal
I want to iterate through one collection containing 1…n documents. I want to put the content of the documents in in ListView. The collection represents the ListView and each document should be one ListTile.
My Firestore Data
I have a Firestore database containing one collection called “current_question” containing multiple documents. Each document contains the details about one question: title, description, date and so on.
My doing so far
I know how to show the data of one document. What I don’t know is, how to load all documents and publish them.
The code for loading one document:
body: FutureBuilder(
future: connectToFirebase(),
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
} else {
return StreamBuilder<DocumentSnapshot>(
stream: database.getQuestions(),
builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
} else {
Map<String, dynamic> items = snapshot.data.data;
print(items);
return ListView.builder(
itemCount: 1,
itemBuilder: (context, i) {
return ListTile(
title: Text(items['Titel'].toString()),
trailing: Text(items['Zaehler'].toString()),
);
}
);
}
},
);
}
}),
Future<void> connectToFirebase() async {
final FirebaseAuth auth = FirebaseAuth.instance;
AuthResult result = await auth.signInAnonymously();
user = result.user;
database = DatabaseService();
}
final CollectionReference aktFragen = Firestore.instance.collection('aktFragen')/*.orderBy('Zaehler')*/;
Stream getQuestions() {
return aktFragen.document('xAGRoZCgiClrpeAPtb5B').snapshots();
}
See the result in the screenshot:
enter image description here
If you want to retrieve all documents then you will have to do a QuerySnapshot instead. Here is one way of doing it:
// Creating an instance of your model with all the users info
List<CustomModelNameHere> _myListSnapshot(QuerySnapshot snapshot) {
return snapshot.documents.map((doc) {
return CustomModelNameHere(
title: doc.data["title"] ?? "",
description: doc.data["description"] ?? "",
);
}).toList();
}
// Get the stream
Stream<List<CustomModelNameHere>> get getQuestions {
return aktFragen.snapshots()
.map(_myListSnapshot);
}
Great answer by #Unbreachable!
This is how I implemented it:
#override
Widget build(BuildContext context) {
return new StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('currentQuestions').snapshots(),
builder: (BuildContext context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
} else {
return new ListView(
children: snapshot.data.documents.map((document) {
return new ListTile(
title: new Text(document['title'].toString()),
subtitle: new Text(document['count'].toString())
);
}).toList()
);
}
}
);
}
I also found a good youTube tutorial for this topic:
https://www.youtube.com/watch?v=Ak_6_pBBe3U&feature=youtu.be