0

I am receiving an error that says:

Bad state: No element
The relevant error-causing widget was: 
  Expanded file:///C:/Users/***/AndroidStudioProjects/***/lib/ui/screens/price-screen.dart:142:23

The error is referring to this part of my code:

Expanded(
                          child: (snapshot.connectionState ==
                                  ConnectionState.waiting)
                              ? Container()
                              : Graph(snapshot.data, crypto, graphType))

I have snapshot.data equal to 'futureData', which is equal to pricesAndTimes. I wrote some print statements in getData() to see if pricesAndTimes is null and it is not null. I'm confused as to why I'm getting this error.

import 'package:bitcoin_ticker/data/coin-data.dart';
import 'package:bitcoin_ticker/ui/components/crypto-card.dart';
import 'package:bitcoin_ticker/ui/components/graph.dart';
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import '../../constants.dart';
import 'package:crypto_font_icons/crypto_font_icons.dart';
import '../components/toggle-button.dart';

class PriceScreen extends StatefulWidget {
  @override
  PriceScreenState createState() => PriceScreenState();
}

class PriceScreenState extends State<PriceScreen> {
  String currency = 'USD';
  String graphType = '1M';
  String crypto = 'LTC';
  Map<String, List<String>> pricesAndTimes = {};
  Future<Map> futureData;

  var isSelectedCrypto = <bool>[false, false, true];
  var isSelectedGraph = <bool>[false, false, true, false, false];
  var isSelectedCurrency = <bool>[true, false, false];

  Future<Map> getData() async {
    try {
      pricesAndTimes = await CoinData(currency, graphType).getCoinData();
  print("pricesAndTimes");
  print(pricesAndTimes);
    } catch (e) {
      print(e);
    }
    return pricesAndTimes;
  }

  @override
  void initState() {
    super.initState();
    futureData = getData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Crypto Watcher'),
      ),
      body: FutureBuilder<Object>(
          future: futureData,
          builder: (context, snapshot) {
            return Stack(
              children: <Widget>[
                Column(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    children: <Widget>[
                      Center(
                          child: ToggleButtons(
                        borderWidth: 10,
                        children: <Widget>[
                          CryptoCard(
                            currency,
                            snapshot.connectionState == ConnectionState.waiting
                                ? '---'
                                : pricesAndTimes['currentCoinPrices'][0],
                            'Bitcoin',
                            Icon(CryptoFontIcons.BTC),
                          ),
                          CryptoCard(
                              currency,
                              snapshot.connectionState ==
                                      ConnectionState.waiting
                                  ? '---'
                                  : pricesAndTimes['currentCoinPrices'][1],
                              'Ethereum',
                              Icon(CryptoFontIcons.ETH)),
                          CryptoCard(
                              currency,
                              snapshot.connectionState ==
                                      ConnectionState.waiting
                                  ? '---'
                                  : pricesAndTimes['currentCoinPrices'][2],
                              'Litecoin',
                              Icon(CryptoFontIcons.LTC)),
                        ],
                        onPressed: (int index) {
                          setState(() {
                            for (int buttonIndex = 0;
                                buttonIndex < isSelectedCrypto.length;
                                buttonIndex++) {
                              if (buttonIndex == index) {
                                isSelectedCrypto[buttonIndex] = true;
                                crypto = cryptoAbbreviation[buttonIndex];
                              } else {
                                isSelectedCrypto[buttonIndex] = false;
                              }
                            }
                          });

                          futureData = getData();
                        },
                        isSelected: isSelectedCrypto,
                        selectedColor: Colors.amber,
                        renderBorder: false,
                        fillColor: Colors.transparent,
                      )),
                      Center(
                        child: ToggleButtons(
                          borderWidth: 0.0,
                          splashColor: null,
                          renderBorder: false,
                          children: <Widget>[
                            ToggleButton('1D'),
                            ToggleButton('5D'),
                            ToggleButton('1M'),
                            ToggleButton('1Y'),
                            ToggleButton('5Y'),
                          ],
                          onPressed: (int index) {
                            setState(() {
                              for (int buttonIndex = 0;
                                  buttonIndex < isSelectedGraph.length;
                                  buttonIndex++) {
                                if (buttonIndex == index) {
                                  isSelectedGraph[buttonIndex] = true;
                                  graphType = graphTypeList[buttonIndex];
                                } else {
                                  isSelectedGraph[buttonIndex] = false;
                                }
                              }
                            });
                            futureData = getData();
                          },
                          isSelected: isSelectedGraph,
                        ),
                      ),
                      Expanded(
                          child: (snapshot.connectionState ==
                                  ConnectionState.waiting)
                              ? Container()
                              : Graph(snapshot.data, crypto, graphType)),
                      Center(
                          child: ToggleButtons(
                        borderWidth: 0.0,
                        splashColor: null,
                        renderBorder: false,
                        children: <Widget>[
                          ToggleButton('USD'),
                          ToggleButton('EUR'),
                          ToggleButton('GBP'),
                        ],
                        onPressed: (int index) {
                          setState(() {
                            for (int buttonIndex = 0;
                                buttonIndex < isSelectedCurrency.length;
                                buttonIndex++) {
                              if (buttonIndex == index) {
                                isSelectedCurrency[buttonIndex] = true;
                                currency = currenciesList[buttonIndex];
                              } else {
                                isSelectedCurrency[buttonIndex] = false;
                              }
                            }
                            futureData = getData();
                          });
                        },
                        isSelected: isSelectedCurrency,
                      )),
                    ]),
                Center(
                    child: (snapshot.connectionState == ConnectionState.waiting)
                        ? CircularProgressIndicator()
                        : Container())
              ],
            );
          }),
    );
  }
}
CuriousCoder
  • 262
  • 4
  • 14

2 Answers2

0

This error happens when your stream return a null value. To make sure the data sent to UI is not null, you can check if the snapshot has data. If not, return a loading indicator. Something like this:

FutureBuilder<Object>(
          future: futureData,
          builder: (context, snapshot) {
            if (!snapshot.hasData) return Center(child: CircularProgressIndicator());
            return Stack(
              children: <Widget>[
              
              // ... other lines
);
Bach
  • 2,928
  • 1
  • 6
  • 16
  • Thank you for your comment but I realized that the issue was in a separate file that I forgot to check. I also already have a loading icon. – CuriousCoder Jan 29 '21 at 02:48
0

I realized that the issue doesn't lie in the code I posted above, but in the referenced Graph file from

Expanded(
                          child: (snapshot.connectionState ==
                                  ConnectionState.waiting)
                              ? Container()
                              : Graph(snapshot.data, crypto, graphType))

I forgot to check that file.

CuriousCoder
  • 262
  • 4
  • 14