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),
        );
      }),
3
  • i think this will help you to get an idea Commented Sep 21, 2018 at 17:41
  • Dont put the whole thing under setState. Call setState when you actually have the data and need to change the UI. Commented Sep 21, 2018 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. Commented Sep 26, 2018 at 18:30

1 Answer 1

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

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.