I wrote code like this:
Container(
height: 250,
child: StreamBuilder(
stream: db.collection("DebrisPeoples").snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Text("yükleniyor");
} else {
final List<DebrisPeopleModel> data = snapshot.data!.docs
.map((e) => DebrisPeopleModel.fromDocument(e))
.toList();
inspect(data);
/*
OUTPUT:
[0]: DebrisPeopleModel
[1]: DebrisPeopleModel
[2]: DebrisPeopleModel
[3]: DebrisPeopleModel
[4]: DebrisPeopleModel
[5]: DebrisPeopleModel
*/
for (var item in data)
return Card(
child: ListTile(
title: Text(item.nameSurname.toString()),
),
);
}
return Container();
},
),
),
When I print it to the console, data shows up, but when I project it to the screen, only one item of data appears. Why could this be?
Wrap the Card with a ListView.builder instead of using the for loop.
Try to return all cards instead of single item like
Container(
//height: 250,
child: StreamBuilder(
stream: db.collection("DebrisPeoples").snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) {
return Text("yükleniyor");
} else {
final List<DebrisPeopleModel> data = snapshot.data!.docs
.map((e) => DebrisPeopleModel.fromDocument(e))
.toList();
inspect(data);
List<Widget> cards = [];
for (var item in data) {
final card = Card(
child: ListTile(
title: Text(item.nameSurname.toString()),
),
);
cards.add(card);
}
return Column(children: cards); // perhaps ListView
}
},
),
)
Related
I am trying to asynchronously pull data from firestore in a streambuilder (all within a list view). The problem with the approach I have now is that nothing displays on the screen. I tried setting state (after i check if the screen is mounted, but to no avail).
I know the correct data is being pulled because it prints to the screen, but for some reason, it just does not display on the screen.
here's a sample of my list view below:
Widget _showFriends() {
return Expanded(
child: StreamBuilder<List<Future<AppUser>>>(
stream: db.friendStream(),
builder: (context, snapshot) {
if(snapshot.hasData) {
print("in here");
final friends = snapshot.data!;
var friend;
String username = "";
String firstName = "";
String photoUrl = "";
return ListView.builder(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
friends[index].then((value) {
friend = value;
username = value.username;
firstName = value.firstName;
//photoUrl = value.photoUrl;
print("friend username -- " + username);
});
return GestureDetector(
onTap: () {
Navigator.of(context).push(MaterialPageRoute(builder: (context)
=> IndividualProfile(
sourceType: SourceType.friends,
name: friend.firstName,
userName: friend.username,
aboutMe: friend.aboutMe,
photoUrl: friend.photoUrl,
individualUid: friend.uid,
)
));
},
child: ListTile(
title: Text(username),
subtitle: Text(firstName),
/*leading: CircleAvatar(
backgroundImage: CachedNetworkImageProvider(photoUrl),
),*/
),
);
},
);
}
else if(snapshot.hasError) {
print(snapshot.error.toString());
return const Center(
child: Text("An error occurred please try again later"),
);
}
else {
return const Center(
child: CircularProgressIndicator(),
);
}
}
)
);
}
Pleas let me know any suggestions. I thoroughly appreciate it!
The problem is that friends[index] is a future. You did not await it before returning GestureDetector.
return GestureDetector(...) would be called before friends[index].then callback. Variable friend would still be null when return GestureDetector(...) is called.
The correct way to wait for it would be with a FutureBuilder.
Try this:
Widget _showFriends() {
return Expanded(
child: StreamBuilder<List<Future<AppUser>>>(
stream: db.friendStream(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final friends = snapshot.data!;
return ListView.builder(
keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
// here I am awaiting friends[index]'s future
return FutureBuilder<AppUser>(
future: friends[index],
builder:
(BuildContext context, AsyncSnapshot<AppUser> snapshot) {
if (snapshot.hasError) {
return const Center(
child: Text(
'An error occurred. Please try again later',
),
);
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator());
}
final friend = snapshot.data!;
return GestureDetector(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => IndividualProfile(
sourceType: SourceType.friends,
name: friend.firstName,
userName: friend.username,
aboutMe: friend.aboutMe,
photoUrl: friend.photoUrl,
individualUid: friend.uid,
),
),
);
},
child: ListTile(
title: Text(friend.username),
subtitle: Text(friend.firstName),
// leading: CircleAvatar(
// backgroundImage:
// CachedNetworkImageProvider(friend.photoUrl),
// ),
),
);
},
);
},
);
}
if (snapshot.hasError) {
print(snapshot.error.toString());
return const Center(
child: Text('An error occurred please try again later'),
);
}
return const Center(child: CircularProgressIndicator());
},
),
);
}
I need help with one case in which my stream builder is returning null values.
I am trying to retrieve a list of services stored in cloud firestore and will display using listview builder later. For now trying to see in the container widget.
I am attaching a snap from my cloud firestore data.
Thanks in Advance.
Here is my code,
return Scaffold(
key: _globalKey,
body: Padding(
padding: EdgeInsets.only(left: 20, top: 50, right: 20),
child: StreamBuilder<QuerySnapshot>(
stream: _firestore
.collection('city')
.doc(Pune)
.collection(Pashan)
.doc('merchantData')
.collection('merchantInfo')
.where('categoryType', isEqualTo: 'Services')
.orderBy('storeType', descending: true)
.snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
print(snapshot.data);
if (snapshot.data != null) {
_storeTypes.clear();
for (var num in snapshot.data.docs) {[enter image description here][1]
if (!_storeTypes.contains(num['storeType'])) {
_storeTypes.add(
num['storeType'],
);
}
}
}
return ListView.builder(
itemCount: _storeTypes.length,
itemBuilder: (context, index) {
return Container(
child: Center(
child: Text(_storeTypes[index]),
),
);
},
);
},
),
),
it's because your trying to use the data before it's fetching from firebase so to avoid the above error add the below code above your if conditions .If you find this answer is correct up vote this answer
if (snapshot.hasError) {
return Center(
child: Text("Something went wrong"),
);
}
if (!snapshot.hasData) {
return Center(
child: Text("No notice found"),
);
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
I am wanting to use two different collections from cloud firestore so I was trying to nest stream builders. However, I cant figure out how to then nest the snapshot. The error I am currently getting is:
flutter: Another exception was thrown: type '(DocumentSnapshot) => dynamic' is not a subtype of type '(QueryDocumentSnapshot) => Widget' of 'f'
This is my code:
new StreamBuilder(
stream: FirebaseFirestore.instance
.collection('moodIcons')
.snapshots(),
builder: (context, snapshot1) {
if (!snapshot1.hasData)
return Text('Loading data... Please Wait');
return StreamBuilder(
stream: FirebaseFirestore.instance
.collection('activityIcons')
.snapshots(),
builder: (context, snapshot2) {
if (!snapshot2.hasData)
return Text('Loading data... Please Wait');
return Container(
height: 100.0,
child: new ListView(
scrollDirection: Axis.horizontal,
children: snapshot1.data.documents
.map<Widget>(
(DocumentSnapshot document1) {
return snapshot2.data.documents
.map<Widget>(
(DocumentSnapshot document2) {
if (document1.data()['display']) {
return new Positioned(
child: new MoodButton(
onTap: () {},
iconData: IconData(
document1.data()['ref'],
fontFamily:
'MaterialIcons')));
}
if (document2.data()['display']) {
return new Positioned(
child: new MoodButton(
onTap: () {},
iconData: IconData(
document2.data()['ref'],
fontFamily:
'MaterialIcons')));
} else {
return (Container());
}
}).toList();
}).toList(),
),
);
});
}),
Any help would be appreciated!
In your code, document1 and document2 are QueryDocumentSnapshot and not DocumentSnapshot.
Also, you are nesting the maps on the moodIcons and the activityIcons.
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
final moodStream = FirebaseFirestore.instance.collection('moodIcons').snapshots();
final activityStream = FirebaseFirestore.instance.collection('activityIcons').snapshots();
return StreamBuilder<QuerySnapshot>(
stream: moodStream,
builder: (context, moodQuerySnapshot) => !moodQuerySnapshot.hasData
? Text('Loading data... Please Wait')
: StreamBuilder<QuerySnapshot>(
stream: activityStream,
builder: (context, activityQuerySnapshot) => !activityQuerySnapshot.hasData
? Text('Loading data... Please Wait')
: Container(
height: 100.0,
child: new ListView(
scrollDirection: Axis.horizontal,
children: [
...moodQuerySnapshot.data.docs,
...activityQuerySnapshot.data.docs,
]
.where((queryDocSnapshot) => queryDocSnapshot.data()['display'])
.map(
(queryDocSnapshot) => Positioned(
child: MoodButton(
onTap: () {},
iconData: IconData(
queryDocSnapshot.data()['ref'],
fontFamily: 'MaterialIcons',
),
),
),
)
.toList(),
),
),
),
);
}
}
I want to display values from my API in a PopupMenuItem in PopupMenuButton. I manage to display it but I want it to be dynamic. Currently, I hard-coded the index of each item because it seems that I cannot do looping inside PopupMenuButton.
`Widget _simplePopup4() => PopupMenuButton<int>(
child: Icon(Icons.arrow_drop_down, color: Colors.orangeAccent),
offset: Offset(0, 100),
itemBuilder: (context) => [
PopupMenuItem(
value: 1,
child: Container(
child: FutureBuilder<SettingCtrl>(
future: getSettingCtrl(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.setTitle == null) {
return Container();
} else {
return Text(snapshot.data.setTitle[1].title); //index 1
}
}
return CircularProgressIndicator();
})),
),
PopupMenuDivider(),
PopupMenuItem(
value: 1,
child: Container(
child: FutureBuilder<SettingCtrl>(
future: getSettingCtrl(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.setTitle == null) {
return Container();
} else {
return Text(snapshot.data.setTitle[2].title); //index 2
}
}
return CircularProgressIndicator();
})),
),
PopupMenuDivider(),
PopupMenuItem(
value: 1,
child: Container(
child: FutureBuilder<SettingCtrl>(
future: getSettingCtrl(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.setTitle == null) {
return Container();
} else {
return Text(snapshot.data.setTitle[3].title); //index 3
}
}
return CircularProgressIndicator();
})),
),
],
);`
//First attempt which gives error: RenderShrinkWrappingViewport does not support returning intrinsic dimensions.
Widget _simplePopup5() => PopupMenuButton(
itemBuilder: (context) {
var list = List<PopupMenuEntry<Object>>();
list.add(
PopupMenuItem(
value: 1,
child: Container(
child: FutureBuilder<SettingCtrl>(
future: getSettingCtrl(),
builder: (context, snapshot) {
if (snapshot.hasData) {
if (snapshot.data.setTitle == null) {
return Container();
} else {
return ListView.builder(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: snapshot.data.setTitle.length,
itemBuilder:
(BuildContext context, int index) {
return Text(snapshot.data.setTitle[index].title);
});
}
}
return CircularProgressIndicator();
})),
),
);
list.add(
PopupMenuDivider(
height: 10,
),
);
return list;
},
icon: Icon(
Icons.settings,
size: 50,
color: Colors.white,
),
);
//Second attempt which gives error: Another exception was thrown: A RenderFlex overflowed by 85 pixels on the bottom.
Widget _simplePopup5() => PopupMenuButton(
itemBuilder: (context) {
var list = List<PopupMenuEntry<Object>>();
list.add(
PopupMenuItem(
value: 1,
child: Container(
child: FutureBuilder<SettingCtrl>(
future: getSettingCtrl(),
builder: (context, snapshot) {
if (snapshot.hasData) {
final listTitle = <Widget>[];
for (var i = 0;
i < snapshot.data.setTitle.length;
i++) {
listTitle.add(SingleChildScrollView(
scrollDirection: Axis.vertical,
child: InkWell(
child:
Text(snapshot.data.setTitle[i].title),
)));
}
if (snapshot.data.setTitle == null) {
return Container();
} else {
return Column(children: listTitle);
}
}
return CircularProgressIndicator();
})),
),
);
list.add(
PopupMenuDivider(
height: 10,
),
);
return list;
},
icon: Icon(
Icons.settings,
size: 50,
color: Colors.white,
),
);
From the screenshot, only one item are clearly displayed which is "MR" while the other item (before item "MR") are displayed in half. Meanwhile, the rest of the item (after item "MR") being replaced with error message.
The screenshot of the second attempt error
The cause of the RenderFlex error is because the child Widget expands beyond the parent Widget. What you can do here is fetch the List of PopupMenu items prior to rendering the PopupMenuButton. With this approach, the List items is ready prior to clicking the PopupMenuButton.
I'm trying to display a Text widget when the collection is empty. However I never can meet the condition to display Text('No Events :('); even when my collection is empty. I presume it's a dart syntax error?
Container(
height: 400,
// width: 500,
child: StreamBuilder<QuerySnapshot>(
stream: Firestore.instance.collection('Events').where("bandId", isEqualTo:identifier ).snapshots(),
builder: (BuildContext context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData)
return new Text('No Events :(');
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return new Text('Loading...');
default:
return new ListView(
children: snapshot.data.documents
.map((DocumentSnapshot document) {
return Dismissible(
key: new Key(document.documentID),
onDismissed: (direction){
Firestore.instance.runTransaction((transaction) async {
DocumentSnapshot snapshot=
await transaction.get(document.reference);
await transaction.delete(snapshot.reference);
});
Fluttertoast.showToast(msg: "Event Deleted");
},
child: CustomCard(
event: document['event'],
location: document['location'],
service: document['service'],
date: document['date'],
),
);
}).toList(),
);
}
},
)),
You are creating a syntax error.
You can not use
new Text("Something");
new ListView(
//
)
You have to specify a Widget which support Children.
You can use Column for displaying multiple Widgets.
Reason: You are specifying If and Switch case.
I would suggest cover your logic inside Switch case only or in If-Else condition.
Container(
height: 400,
// width: 500,
child: StreamBuilder(
stream: Firestore.instance.collection('Events').where("bandId", isEqualTo:identifier ).snapshots(),
builder: (BuildContext context,
AsyncSnapshot snapshot) {
return new Column(
children: [
if (!snapshot.hasData)
new Text('No Events :('),
switch (snapshot.connectionState) {
case ConnectionState.waiting:
new Text('Loading...');
default:
new Container(
childe: ListView(
children: snapshot.data.documents
.map((DocumentSnapshot document) {
return Dismissible(
key: new Key(document.documentID),
onDismissed: (direction){
Firestore.instance.runTransaction((transaction) async {
DocumentSnapshot snapshot=
await transaction.get(document.reference);
await transaction.delete(snapshot.reference);
});
Fluttertoast.showToast(msg: "Event Deleted");
},
child: CustomCard(
event: document['event'],
location: document['location'],
service: document['service'],
date: document['date'],
),
);
}).toList(),
),
),
}
]),
},
)
);