Reputation: 59
I am currently facing a problem with Flutter and Firebase.
I want to display data from my Firebase Databse.
Most of the code is from Fluttery's video on Tinder Cards, I just wanted to learn how to display name, photos, age and biography on the cards. I only want to do name and description for now.
My current code:
class _ProfileCardState extends State<ProfileCard> {
Widget _buildProfileSynopsis() {
return new Positioned(
left: 0.0,
right: 0.0,
bottom: 0.0,
child: new Container(
padding: const EdgeInsets.all(24.0),
child: new Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new StreamBuilder<Event>(
stream: FirebaseDatabase.instance
.reference()
.child('items')
.child('-LD2vzOCd54yEFNXJpGj')
.onValue,
builder: (BuildContext context, AsyncSnapshot<Event> event) {
if (!event.hasData)
return new Center(child: new Text('Loading...'));
Map<dynamic, dynamic> data = event.data.snapshot.value;
return new Text('${event.data.snapshot.value}', style: new TextStyle(
fontSize: 30.0)
);
},
),
new StreamBuilder<Event>(
stream: FirebaseDatabase.instance
.reference()
.child('items')
.child('-LD2vzOCd54yEFNXJpGj')
.onValue,
builder: (BuildContext context, AsyncSnapshot<Event> event) {
if (!event.hasData)
return new Center(child: new Text('Loading...'));
Map<dynamic, dynamic> data = event.data.snapshot.value;
return new Text('-${event.data.snapshot.value}');
},
),
],
),
),
new Icon(
Icons.info,
color: Colors.black,
),
],
),
),
);
}
@override
Widget build(BuildContext context) {
return new Container(
decoration: new BoxDecoration(
borderRadius: new BorderRadius.circular(10.0),
boxShadow: [
new BoxShadow(
color: const Color(0x11000000),
blurRadius: 5.0,
spreadRadius: 2.0,
),
],
),
child: ClipRRect(
borderRadius: new BorderRadius.circular(10.0),
child: new Material(
child: new Stack(
fit: StackFit.expand,
children: <Widget>[
_buildProfileSynopsis(),
],
),
),
),
);
}
class Males {
String name, description;
Males(this.name, this.description);
}
}
Images:
As you can see in the screenshot of my Firebase, every person has a unique key, which makes it hard to refer to the individual data. This is my main problem, as I do not know how to save the accountkey in a String, so I can do .child(accountkey).
All of the youtube tuturials show a Listview, but that just displays the data in a list on the card, which isn't useful because every card shows every user.
Thanks in advance, let me know if you have any questions. I hope that you can help :)
Upvotes: 0
Views: 5479
Reputation: 3261
You were very close.
You declare the Map Map<dynamic, dynamic> data = event.data.snapshot.value;
but then don't use it, and instead just use event.data.snapshot.value
in your Text
widget. event.data.snapshot.value
is the all of the data under the child in Firebase. Which is why you see all of the data in both the name and the description. Instead to get the name you should use data['name']
and the description data['description']
. The string in the square brackets are the keys in the firebase database.
Another suggestion would be to display all user data in a Column
in one StreamBuilder
as you wont download the data twice. In a simple example like this it doesn't matter, but when you start dealing with bigger data this could impact loading times.
Here is a revised version of _ProfileCardState
that (hopefully) will work for you. Let me know if you have any more questions.
class _ProfileCardState extends State<ProfileCard> {
Widget _buildProfileSynopsis() {
return new Positioned(
left: 0.0,
right: 0.0,
bottom: 0.0,
child: new Container(
padding: const EdgeInsets.all(24.0),
child: new Row(
mainAxisSize: MainAxisSize.max,
children: <Widget>[
new Expanded(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
new StreamBuilder<Event>(
stream: FirebaseDatabase.instance
.reference()
.child('items')
.child('-LD2vzOCd54yEFNXJpGj')
.onValue,
builder:
(BuildContext context, AsyncSnapshot<Event> event) {
if (!event.hasData)
return new Center(child: new Text('Loading...'));
Map<dynamic, dynamic> data = event.data.snapshot.value;
return Column(children: [
new Text('${data['name']}',
style: new TextStyle(fontSize: 30.0)),
new Text('-${data['description']}')
]);
},
),
],
),
),
new Icon(
Icons.info,
color: Colors.black,
),
],
),
),
);
}
Here is an image:
Upvotes: 1
Reputation: 267
Good morning
My method is quietly different from you. I always write a class to get the data from the datasource then I use it every where. I think you are new in this framework so I will explain by steps
Get data class is :
class GetItemsFromDb {
static Future<List> getItems( ) async {
Completer<List> completer = new Completer<List>();
FirebaseDatabase.instance
.reference()
.child("males")
.once()
.then( (DataSnapshot snapshot) {
//print(snapshot.value);
List map = snapshot.value;
completer.complete(map);
} );
return completer.future;
}
}
as you said, you want all the items in the male. Firebase database will give you a list of maps( Map is a dictionary).
I will rewrite your Males object again
class Males {
String names;
String desc;
// empty constructor
Males();
// constructor for firebase databases
Males.fromMap(Map<String, dynamic> map){
names = map["name"];
desc = map["description"];
}
}
Now you put this in your view
List<Males> _males = [];
@override
void initState() {
// TODO: implement initState
super.initState();
GetItemsFromDb.getItems().then((list){
print("Now the list is here");
setState(() {
for (int i=0; i < list.length; i++) {
Map<String, dynamic> map = list[i];
Males male = new Males.fromMap(map);
_males.add(male);
}
});
});
}
now you have the full list from firebase and their data, and you can display them all
Upvotes: 2