3

I had referred to the cookbook.

https://flutter.dev/docs/cookbook/networking/fetch-data

The sample code is to get single JSON data.

I'm trying to get following multiple JSON data from StatefulWidget. And I would like to show season data in each grid by GridView.

[
  {"id":1,"season_end":"1999/01","season_name":"First","season_start":"1999/08"}, 
  {"id":2,"season_end":"1999/07","season_name":"Second","season_start":"1999/02"}, 
  {"id":3,"season_end":"2000/01","season_name":"Third","season_start":"1999/08"}, 
  {"id":4,"season_end":"2000/07","season_name":"Forth","season_start":"2000/02"}
]

However I have no idea to write better code like below.

class _HomePageState extends State<HomePage> {
  Future<List<Season>> seasons;

  @override
  void initState(){
    super.initState();
    seasons = fetchSeasons();
  }

  Widget build(BuildContext context) {
    return Scaffold(
      body: GridView.builder(
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            ...
          ),
          itemBuilder: (context, index){
            return seasons[index].toString();
          }
      )
    )
  }
}

I should have used FutureBuilder<List<Season>>, But I don't know how to use with GridView. Do you have any advice? Please.

Future<List<Season>> fetchSeasons() async {
  final response =
  await http.get('http://10.0.2.2:4000/api/seasons');

  if(response.statusCode == 200){
    Iterable list = json.decode(response.body);
    var seasons = list.map((season) => Season.fromJson(season)).toList();
    return seasons;
  }else{
    print('Error!!');
    throw Exception('Failed to Load Post');
  }
}
class Season {
  final int id;
  final String season_name;
  final String season_start;
  final String season_end;

  Season({this.id, this.season_name, this.season_start, this.season_end});

  factory Season.fromJson(Map<String, dynamic> json){
    return Season(
      id: json['id'],
      season_name: json['season_name'],
      season_start: json['season_start'],
      season_end: json['season_end']
    );
  }
}

2 Answers 2

6

The problem is that seasons is a Future, not a List, that's why you can't use it like a list.

If you want to access the list of that Future, you need to use FutureBuilder, like this:

Widget build(BuildContext context) {
  return Scaffold(
    body: FutureBuilder<List<Season>>(
      future: seasons,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return GridView.builder(
              itemCount: snapshot.data.length,
              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              ...
              ),
              itemBuilder: (context, index) {
                return Text("${snapshot.data[index].season_name}");
              }
          );
        } else if (snapshot.hasError) {
          return Text("Error");
        }
        return Text("Loading...");
      },
    ),
  );
}
Sign up to request clarification or add additional context in comments.

Comments

2

There are couple of ways to do that with FutureBuilder you can do like this,in this case you dont need to use initstate or a Stateful widget the futurebuilder automatically calls the method fetchSeasons() as it gets rendered on screen and the result is received as a snapshot which can be accessed as below.

FutureBuilder<List<seasons>>(
future:fetchSeasons(),
builder:(BuildContext context,AsyncSnapshot <List<seasons>>snapshot){
          snapshot.hasData?
          return GridView.builder(
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            ...
          ),
          itemCount:snapshot.data.length,
          itemBuilder: (context, index){
            return Column(
             children: <Widget>[
                    Text('${snapshot.data[index]['id']}'),
                    Text('${snapshot.data[index]['season_name']}'),
                    Text('${snapshot.data[index]['season_end']}'),
                    Text('${snapshot.data[index]['season_start']}'),
                ]
               ):Center(child:CircularProgressIndicator());
          }
});

4 Comments

I don't understand why the number of grids is more than 4? It returns more grids and have out of index.
Ops. I forget set itemCount. Sorry.
Text('${snapshot.data[index]['season_name']}', has error. The operator [] isn't defined for the class Season. Actually it has.
so Basically it seems that fetchSeasons() is not returning a list

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.