将数据从Firebase加载到Flutter中的DropdownButton中

时间:2020-03-31 17:56:28

标签: firebase flutter dropdown

我是Flutter中使用Firebase的新手,我正在尝试将存储在Firebase中的某些数组加载到DropdownButton中。

当我从按钮调用它时,这段代码起作用。它返回我可以在屏幕上打印的饮料列表:

Future<List<String>> get drinks async {
    QuerySnapshot docs = await _constantes.getDocuments();
    List<String> res = List();
    List<Map<String, dynamic>> datos = List();

    for (var d in docs.documents) {
      datos.add(d.data);
    }

    for (var d in datos[0]['drinks'].toList()) {
      res.add(d.toString());
    }

    return res;
  }

但是我的问题是我想将此列表加载到一个DropdownButton中,所以当应用向他显示以下形式时,用户可以选择其中一种饮料:

DropdownButtonFormField(
            hint: Text('Choose a drink'),
            value: _currentDrink ?? 'Water',
            items: _db.drinks.then((drinks) {
              List<DropdownMenuItem> datos = List();

              for (var d in drinks) {
                datos.add(DropdownMenuItem(
                  value: d,
                  child: Text(d),
                ));
              }
              return datos;
            }),
            onChanged: (val) => setState(() => _currentDrink = val),
          ),

但是它不起作用,因为结果是未来。

我该如何解决?

谢谢。

3 个答案:

答案 0 :(得分:0)

分配一个空列表[]进行下拉,直到获取饮料为止,并且当获取饮料时,我们将分配饮料列表。饮料列表将在我们的将来完成后获取项目。您需要在方法的initState中调用此future,因此当页面为打开它获取饮料,然后将其分配到饮料列表。Dropdown将保持为空,直到获取饮料为止。 (以防您在下拉菜单中显示进度指示器,直到在将来的构建器中提取饮料包装下拉列表时为止)

List<String> drinks = List();

Future<List<String>> get drinks async {
  QuerySnapshot docs = await _constantes.getDocuments();
  List<String> res = List();
  List<Map<String, dynamic>> datos = List();

  for (var d in docs.documents) {
    datos.add(d.data);
  }

  for (var d in datos[0]['drinks'].toList()) {
    res.add(d.toString());
  }

  setState(() {
    drinks = res;
  });

  return res;
}

DropdownButtonFormField(
      hint: Text('Choose a drink'),
      value: _currentDrink ?? 'Water',
      items: drinks == null? []: drinks.map((drink) {
          return DropdownMenuItem<String>(
         child: Text(drink),
             value: drink,
              );
          }).toList(),
            onChanged: (val) => setState(() => _currentDrink = val),
),

答案 1 :(得分:0)

将其包装在StreamBuilder中。假设_constantes是您的Firebase集合,而不是使用_constantes.getDocuments()进行查询,而是从_constantes.snapshots()返回流:

StreamBuilder<List<DocumentSnapshot>>(
  stream: _drinkStream,
  builder: (context, snapshot) {
    return snapshot.hasData
        ? DropdownButton(
            onChanged: (value) {},
            items: [
              for (var child in snapshot.data)
                DropdownMenuItem(
                  child: Text(
                    child.data['name'],
                  ),
                  value: child,
                ),
            ],
          )
        : Container();
  },
)

答案 2 :(得分:0)

从Firebase获取数据后,您可以构建下拉窗口小部件,并且如果要在加载数据之前或没有找到数据之前放水,那么以下解决方案可能是最适合您的。

方法注释部分用于您的情况,而un注释部分用于演示。

class DeleteWidget extends StatefulWidget {
  const DeleteWidget({Key key}) : super(key: key);

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

class _DeleteWidgetState extends State<DeleteWidget> {
  String initdata = 'water';
  List<String> _getdata = List();
  @override
  void initState() {
    super.initState();
    getdatafromAPI();
  }

  void getdatafromAPI() async {
    /*
    _db.drinks.then((drinks){
        setState((){
            _getdata.addAll(drinks);
            initdata = _getdata[0];
        });
    });
    */
    await Future.delayed(Duration(seconds: 1));
    setState(() {
      _getdata.addAll(['coffee', 'tea', 'greentea']);
      initdata = _getdata[0];
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('test app'),
      ),
      body: Container(
        child: Center(
          child: DropdownButton(
            items: _getdata.length > 0
                ? _getdata.map((e) {
                    return DropdownMenuItem<String>(
                      child: Text(e.toString()),
                      value: e.toString(),
                    );
                  }).toList()
                : [
                    DropdownMenuItem<String>(
                      child: Text("water"),
                      value: 'water',
                    )
                  ],
            value: initdata,
            onChanged: (value) {
              setState(() {
                initdata = value;
              });
            },
          ),
        ),
      ),
    );
  }
}