Asyraf Dayan
Asyraf Dayan

Reputation: 3071

Flutter List<String> JSON into a Widget

I have a JSON file which is in the assets folder

States.json

{
  "name" : "State List",
  "states" : [
   "Johor",
    "Kedah",
    "Kelantan",
    "Kuala Lumpur",
    "Melaka",
    "Negeri Sembilan",
    "Pulau Pinang",
    "Perak",
    "Perlis",
    "Pahang",
    "Terengganu",
    "Sabah",
    "Sarawak",
    "Selangor",
    "Wilayah Persekutuan"
  ]
}

I made a model class for the states:

state_model.dart

class States{

  String name;
  List<String> states;

  States({this.name, this.states});

  factory States.fromJson(Map<String, dynamic> json){

    var statesJson = json["states"];
    List<String> stateList = new List<String>.from(statesJson);

    return States(
      name: json["name"],
      states: stateList
    );
  }
}

This is the main.dart file:

import 'package:flutter/material.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'dart:async' show Future;
import 'dart:convert';
import 'package:state_json/model/state_model.dart';

//get the assets
Future<String> loadAssets() async{
  return await rootBundle.loadString('assets/states.json');
}

//get the states from the assets
Future loadStates() async{
  String jsonState =  await loadAssets();
  final jsonResponse = json.decode(jsonState);

  States states = new States.fromJson(jsonResponse);
  print(states.states);
  return states.states;
}

void main() {
  runApp(new MyApp());
}

class MyApp extends StatefulWidget {
  @override
  MyAppState createState() {
    return new MyAppState();
  }
}

class MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        home: new Scaffold(
          appBar: new AppBar(
              title: new Text("States JSON")
          ),
            body: new FutureBuilder(
                future: loadStates(),
                builder: (context, snapshot){
                  if(snapshot.hasData){
                    return new ListView.builder(
                        itemBuilder: (context, index){
                          new ListTile(
                            title: new Text("${snapshot.data}"),
                          );
                        });
                  }else{
                    return new Center(child: new CircularProgressIndicator());
                  }
                })
        )
    );
  }
}

The problem I am currently facing is, I could print out the values of the string in the terminal just fine.

I/flutter (16482): [Johor, Kedah, Kelantan, Kuala Lumpur, Melaka, Negeri Sembilan, Pulau Pinang, Perak, Perlis, Pahang, Terengganu, Sabah, Sarawak, Selangor, Wilayah Persekutuan]

But I am clueless as to how am I supposed to insert the values into the FutureBuilder.builder, which goes to a ListView.builder and subsequently into the ListTile to show the list of the States.

Any help is very much appreciated.

Upvotes: 1

Views: 4100

Answers (2)

1ujn4s
1ujn4s

Reputation: 489

To simplify @Letsar's answer :

We can also pass the itemCount parameter to ListView.builder to specify the number of elements in the list, instead of returning null to mark the index as not applicable. Example below:

return new ListView.builder(
    itemCount: snapshot?.data?.length,
    itemBuilder: (context, index) {
        return new ListTile(
          title: new Text("${snapshot.data[index]}"),
        );
    }
);

Upvotes: 2

Romain Rastel
Romain Rastel

Reputation: 5622

There are maybe two issues here:

  1. There are no return statement in the itemBuilder. So it returns null.
  2. The return type of loadStates() is a Future. I think it should be a Future<List<String>>.

Then you can access the data through the index:

return new ListView.builder(
  itemBuilder: (context, index){
    if(index >= snapshot?.data?.length ?? 0) return null;

    return new ListTile(
      title: new Text("${snapshot.data[index]}"),
    );
});

Note: I didn't test the code.

Upvotes: 2

Related Questions