Thorvald
Thorvald

Reputation: 3563

Flutter - "Range error (length)" when trying to parse local json data

I have a JSON file that has a text and each sentence is in a separate JSON object, the user shoud be able to navigate between sentenes with next() and previous() but when the app loads I get this error:

RangeError (index): Invalid value: Valid value range is empty: 0

until I press any other button on the screen that's when the text loads and get displayed.

The card itself is a statefulWidget and here's my code:

class _BottomCardsState extends State<BottomCards>{

  bool isLoadingEnded = false;

  Future<Null> getAllData() async{
    await DefaultAssetBundle.of(context).loadString('assets/json/data.json').then((response){
      isLoadingEnded = true;
      var decodedData = json.decode(response);
        for(Map d in decodedData){
          dataList.add(Data.fromJson(d));
        }      
    });
  }

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

  int dataIndex = 0;

  @override
  Widget build(BuildContext context) {
    int myNbr = dataList[dataIndex].id;
    return Container(
      child: Material(
        color: Colors.transparent,
        child: Card(
          margin: EdgeInsets.symmetric(horizontal: 10.0),
          elevation: 6.0,
          child: Container(
            alignment: Alignment.topCenter,
            padding: EdgeInsets.symmetric(horizontal: 12.0,),
            child: Column(
              children: <Widget>[
                Row(
                  children: <Widget>[
                    IconButton(                  
                      splashColor: gradientStart,
                      icon: Icon(Icons.keyboard_arrow_left,),
                      onPressed: () {_previous();},
                    ),
                    IconButton(
                      splashColor: gradientStart,
                      icon: Icon(Icons.keyboard_arrow_right,),
                      onPressed: () {_next();},
                    ),
                  ],
                ),
                SizedBox(height: 4.0,),
                isLoadingEnded == true ? Container(
                  child: Column(
                    children: <Widget>[
                      Row(
                        mainAxisAlignment: MainAxisAlignment.start,
                        mainAxisSize: MainAxisSize.max,
                        children: <Widget>[
                          Expanded(                  
                            child: InkWell(
                              splashColor: Colors.lightBlue[100],
                              onTap: (){},
                              //the paragraph gets displayed here
                              child: Text(dataList[dataIndex].paragraph,
                            ),
                          ),
                        ],
                      ),
                      SizedBox(height: 8.0,),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.end,
                        mainAxisSize: MainAxisSize.max,
                        children: <Widget>[
                          Chip(
                            backgroundColor: secondaryDark,
                            label: Text('Number: $myNbr',
                            style: TextStyle(color: Colors.white, fontSize: 10.0, fontWeight: FontWeight.w500),),
                          ),
                        ],
                      ),
                    ],
                  ),
                ): Center(child: loadingIndicator(),),
                SizedBox(height: 6.0),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

` My JSON format:

{
    "id": 1,
    "paragraph": "lorem ipsum"
},
...

Upvotes: 0

Views: 558

Answers (2)

satish
satish

Reputation: 1374

import 'package:flutter/services.dart' show rootBundle;

the first of fall your data is like a map, and you are trying to store in a list. as I can see your data is the type of map.

{
    "id": 1,
    "paragraph": "lorem ipsum"
}

Future<void> getAllData() async {
 final res= await rootBundle.loadString('assets/config.json');
 final json = jsonDecode(res.body);
 var parse = json as Map; 
 Data data=Data.fromJson(parse);
}

and if JSON is contained list data then

[
{
    "id": 1,
    "paragraph": "lorem ipsum"
},
{
    "id": 1,
    "paragraph": "lorem ipsum"
}
]

then

 Future<void> getAllData() async {
      final res= await rootBundle.loadString('assets/config.json');
     final json = jsonDecode(res.body);
     var parse = json as List;
     parse.forEach((d){ 
     dataList.add(Data.fromJson(d));
     });
    }

Upvotes: 0

Abhay Koradiya
Abhay Koradiya

Reputation: 2117

You need to wait until data is filled up.

change your getAllData method. Like,

Future<List<Data>> getAllData() async{
    var response = await DefaultAssetBundle.of(context).loadString('assets/json/data.json')
    var decodedData = json.decode(response);
    for(Map d in decodedData){
        dataList.add(Data.fromJson(d));
    }  
    return dataList;
}

and now wait on build method. Like,

@override
  Widget build(BuildContext context) {
   return FutureBuilder<List<Data>>(
        future: getAllData(),
        builder: (context, snapshot) {
          if (snapshot.hasData) {
             print("Here you can get data "+snapshot.data.toString());
            //you can put your ui here
          } else {
            print("Waiting mode");
            return Container(
              color: Colors.blue,
            );
          }
        },
      )
}

Upvotes: 1

Related Questions