1

I'm trying to fetch data from firestore and display it in a dropdown menu. I tried declaring the list like the following:   List makes = [''] but I can’t view the data until I click on another field and the dropdown gets populated at multiple occasions. I have it in a method because eventually, I would like to create a second dropdown where there’s a condition in the database query.

ex. If Toyota is selected display all the models for that particular make.

new StreamBuilder<QuerySnapshot>(
      stream: Firestore.instance.collection("makesModels").snapshots(),
      builder: (context, snapshot) {
        if (!snapshot.hasData) return new Text("Please wait");
        return new DropdownButton(
          items: snapshot.data.documents.map((DocumentSnapshot document) {
            return DropdownMenuItem(
                value: document.data["make"],
                child: new Text(document.data["make"]));
          }).toList(),
          value: category,
          onChanged: (value) {
            setState(() {
              category = value;
            });
          },
          hint: new Text("Makes"),
          style: TextStyle(color: Colors.black),
        );
      }),
      new StreamBuilder<QuerySnapshot>(
      stream: Firestore.instance.collection("makesModels").where('make', isEqualTo: category).snapshots(),
      builder: (context, snapshot) {

        if (!snapshot.hasData) return new Text("Please wait");
        return new DropdownButton(
          items: snapshot.data.documents.map((DocumentSnapshot document) { 
            for(int i = 0; i < document.data['models'].length; i++){

              print(document.data['models'][i]);
              return new DropdownMenuItem(
              value: document.data['models'][i],
                child: new Text(document.data['models'][i].toString()),
              );
            }   

            }).toList(),
          value: models,
          onChanged: (value) {
            print(value);

            setState(() {
              models = value;
            });
          },
          hint: new Text("Models"),
          style: TextStyle(color: Colors.black),
        );
      }),
Ouardia
  • 349
  • 1
  • 4
  • 14
  • i think [this](https://stackoverflow.com/a/51672627/4511702) will help you to get an idea – Raouf Rahiche Sep 21 '18 at 17:41
  • Dont put the whole thing under setState. Call setState when you actually have the data and need to change the UI. – user1462442 Sep 21 '18 at 19:08
  • Thanks to both. Actually I did try not putting everything in setstate but that didn't work. I was able to get it to work partially. Any thoughts on how to irritate through all the models and display it in the dropdown? If I print the model value, I can see both but as soon as I add return new DropdownMenuItem, I can only display the first value. – Ouardia Sep 26 '18 at 18:30

1 Answers1

9

Checking the snippet you've provided, it seems that the app displays two DropdownButton. To display a default selected item on the dropdown, an item should be set on value. In my approach, I've set a boolean to check if there's a need to set a default value.

The Firestore data used in this sample app accesses two Firestore collections: carMake and cars (contains 'makeModel').

carMake collection

carMake collection

cars collection containing 'makeModel'

enter image description here

Complete app

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // Initialize Firebase
  await Firebase.initializeApp();
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  var carMake, carMakeModel;
  var setDefaultMake = true, setDefaultMakeModel = true;

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    debugPrint('carMake: $carMake');
    debugPrint('carMakeModel: $carMakeModel');
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Column(
        children: [
          Expanded(
            flex: 1,
            child: Center(
              child: StreamBuilder<QuerySnapshot>(
                stream: FirebaseFirestore.instance
                    .collection('carMake')
                    .orderBy('name')
                    .snapshots(),
                builder: (BuildContext context,
                    AsyncSnapshot<QuerySnapshot> snapshot) {
                  // Safety check to ensure that snapshot contains data
                  // without this safety check, StreamBuilder dirty state warnings will be thrown
                  if (!snapshot.hasData) return Container();
                  // Set this value for default,
                  // setDefault will change if an item was selected
                  // First item from the List will be displayed
                  if (setDefaultMake) {
                    carMake = snapshot.data.docs[0].get('name');
                    debugPrint('setDefault make: $carMake');
                  }
                  return DropdownButton(
                    isExpanded: false,
                    value: carMake,
                    items: snapshot.data.docs.map((value) {
                      return DropdownMenuItem(
                        value: value.get('name'),
                        child: Text('${value.get('name')}'),
                      );
                    }).toList(),
                    onChanged: (value) {
                      debugPrint('selected onchange: $value');
                      setState(
                        () {
                          debugPrint('make selected: $value');
                          // Selected value will be stored
                          carMake = value;
                          // Default dropdown value won't be displayed anymore
                          setDefaultMake = false;
                          // Set makeModel to true to display first car from list
                          setDefaultMakeModel = true;
                        },
                      );
                    },
                  );
                },
              ),
            ),
          ),
          Expanded(
            flex: 1,
            child: Center(
              child: carMake != null
                  ? StreamBuilder<QuerySnapshot>(
                      stream: FirebaseFirestore.instance
                          .collection('cars')
                          .where('make', isEqualTo: carMake)
                          .orderBy("makeModel").snapshots(),
                      builder: (BuildContext context,
                          AsyncSnapshot<QuerySnapshot> snapshot) {
                        if (!snapshot.hasData) {
                          debugPrint('snapshot status: ${snapshot.error}');
                          return Container(
                            child:
                            Text(
                                'snapshot empty carMake: $carMake makeModel: $carMakeModel'),
                          );
                        }
                        if (setDefaultMakeModel) {
                          carMakeModel = snapshot.data.docs[0].get('makeModel');
                          debugPrint('setDefault makeModel: $carMakeModel');
                        }
                        return DropdownButton(
                          isExpanded: false,
                          value: carMakeModel,
                          items: snapshot.data.docs.map((value) {
                            debugPrint('makeModel: ${value.get('makeModel')}');
                            return DropdownMenuItem(
                              value: value.get('makeModel'),
                              child: Text(
                                '${value.get('makeModel')}',
                                overflow: TextOverflow.ellipsis,
                              ),
                            );
                          }).toList(),
                          onChanged: (value) {
                            debugPrint('makeModel selected: $value');
                            setState(
                              () {
                                // Selected value will be stored
                                carMakeModel = value;
                                // Default dropdown value won't be displayed anymore
                                setDefaultMakeModel = false;
                              },
                            );
                          },
                        );
                      },
                    )
                  : Container(
                      child: Text('carMake null carMake: $carMake makeModel: $carMakeModel'),
                    ),
            ),
          ),
        ],
      ),
    );
  }
}

Demo

demo

Omatt
  • 8,564
  • 2
  • 42
  • 144