Загрузка данных из Firebase в DropdownButton в Flutter - PullRequest
0 голосов
/ 31 марта 2020

Я новичок во 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 голосов
/ 31 марта 2020

Оберните это в StreamBuilder. Вместо запроса _constantes.getDocuments() верните поток из _constantes.snapshots(), предполагая, что _constantes является вашей коллекцией firebase:

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();
  },
)
0 голосов
/ 31 марта 2020

вы можете создать выпадающий виджет после того, как вы получите данные из своей базы данных, и если вы хотите показывать воду до того, как данные будут загружены или данные не найдены, тогда следующие решения могут быть лучше для вас.

в комментарии метода часть для вашего случая, а часть без комментариев для демо.

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;
              });
            },
          ),
        ),
      ),
    );
  }
}
0 голосов
/ 31 марта 2020

Назначьте пустой список [] для раскрывающегося списка до тех пор, пока напитки не будут получены, а при получении мы назначим список напитков. Список напитков получит элементы после того, как наше будущее будет завершено. Вам нужно вызывать это будущее в initState вашего метода, чтобы, когда страница Открывается, что получает напитки, а затем назначает его в список напитков. Выпадающий будет оставаться пустым, пока напитки не будут получены. (Если вы хотите, чтобы индикатор прогресса отображался в выпадающем списке, пока не будут получены напитки, выпадающий список в будущем сборщике)

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),
),
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...