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:

Importan screenshot

Image of my Database

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 :)


Solution 1: Yousuf AL-Mawali

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


Solution 2: Mans

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:

firebase data