Christer
Christer

Reputation: 3076

Flutter firebase_database get children

Hi I want to deserialise the snapshot from the realtime database to a Company object and add it to a _companies list. But I keep getting an error...

This is what I have so far:

  List<Company> _companies = [];
  @override
  void initState() {
    // TODO: implement initState
    super.initState();

    getItems().then((list){
      print("Now the list is here");

      setState(() {
        for (int i=0; i < list.length; i++) {
          Map<String, dynamic> map = list[i];

          Company company = new Company.fromMap(map);
          _companies.add(company);
        }
      });

    });
  }

  static Future<List> getItems( ) async {
    Completer<List> completer = new Completer<List>();

    FirebaseDatabase.instance
        .reference()
        .child("Companies")
        .once()
        .then( (DataSnapshot snapshot) {

      List map = snapshot.value; //It fails here
      completer.complete(map);
    } );

    return completer.future;
  }

This is my Company class:

class Company {
  String key;
  String category;
  String company_name;
  String company_url;
  String country;
  String description;
  String email;
  String faq_url;
  String instagram_url;
  String logo_url_image;
  String p_category;
  String parent_company_ok;
  String timestamp;

  Company();

  Company.fromSnapshot(DataSnapshot snapshot)
      : key = snapshot.key,
      category = snapshot.value['category'],
      company_name = snapshot.value['company_name'],
      company_url = snapshot.value['company_url'],
      country = snapshot.value['country'],
      description=  snapshot.value['description'],
      email = snapshot.value['email'],
      faq_url = snapshot.value['faq_url'],
      instagram_url = snapshot.value['instagram_url'],
      logo_url_image = snapshot.value['logo_url_image'],
      p_category = snapshot.value['p_category'],
      parent_company_ok = snapshot.value['parent_company_ok'],
      timestamp = snapshot.value['timestamp'];
}

How ever, it fails in getItems( ) on List map = snapshot.value;. With the exeption: _InternalLinkedHashMap<dynamic, dynamic>' is not a subtype of type 'List<dynamic>'

Also if anyone can provide the code for showing the children in a List widget I would be very happy :)

Here is my data structure in firebase realtime database:

enter image description here

Upvotes: 0

Views: 3561

Answers (2)

Marcos Boaventura
Marcos Boaventura

Reputation: 4741

Well as the error message says snapshot.value is not a List but it is a map so the line List map = snapshot.value; will always fail. Since you are reading Companies node tree from your database this will return a map of maps, something like Map<String, Map<dynamic,dynamic>> with all data from respective node. I will provide you a function that parse your Json data in Company object and i will left some comments in source code to try explain you the process. It's simple.

List<Company> _parseData(DataSnapshot dataSnapshot) {
    List<Company> companyList =new List();

    // here you replace List map = snapshot.value with... dataSnapshot.val()
    Map<String, dynamic> mapOfMaps = Map.from( dataSnapshot.val() );
    //actually dynamic here is another Map, String are the keys like -LXuQmyuF7E... or LXuSkMdJX... 
   //of your picture example and dynamic other Map    

    //in next lines we will interate in all values of your map
    //remeber that the values are maps too, values has one map for each company. 
    //The values are Map<String, dynamic>
    //in this case String are keys like category, company_name, country, etc... 
    //and dynamics data like string, int, float, etc

    //parsing and adding each Company object to list
    mapOfMaps.values.forEach( (value) {
      companyList.add(
          //here you'll not use fromSnapshot to parse data,
          //i thing you got why we're not using fromSnapshot
          Company.fromJson( Map.from(value) )
      );
    });

    return companyList;

  }

Note you will use Company.fromSnapshot(snapshot) when you read a specific company from your db, something like ...

// just to illustrate
var snapshot = await FirebaseDatabase.instance
      .reference()
      .child("Companies")
      .child(companyId).once();
Company.fromSnapshot( snapshot );

because in this case the snapshot.value is a single map. Well another thing is, take a look at you initState method in your statefull widget, i don't know if is a good approach call setState inside initState method even after a Future execution. This is just an advise.

Upvotes: 3

David Benitez Riba
David Benitez Riba

Reputation: 918

snapshot.value returns a Map and you are using a List to store it. Maybe the easiest solution here is to use the var type to declare your map variable:

var map = snapshot.value;

but it's a good practice to set a type whenever you can to your variables. So, in this case the best option is to set it like this:

Map<dynamic, dynamic> map = snapshot.value;

Check dart's documentation to improve your skills in useing maps and list and how they work Lists docs Maps docs

Upvotes: 1

Related Questions