15

Following an online example I have the following code:

_fetchData() async {
    setState(() {
      isLoading = true;
    });

    final response = await http.get(
        "https://apiurl...");

    if (response.statusCode == 200) {
      print(json.decode(response.body).runtimeType); // _InternalLinkedHashMap<String, dynamic>

      list = (json.decode(response.body) as List)
          .map((data) => Model.fromJson(data))
          .toList();

      setState(() {
        isLoading = false;
      });
    } else {
      throw Exception('Failed to load');
    }
  }

Which returns this error:

Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'List<dynamic>' in type cast

This is the response from the API:

{"results":[{"docid":"123434","title":"A title"}, ...]}

Model:

class Model {
  final String title;
  final String docid;

  Model._({this.title, this.docid});

  factory Model.fromJson(Map<String, dynamic> json) {
    return new Model._(
      title: json['title'],
      docid: json['docid'],
    );
  }
}

I understand that the above factory is expecting the argument to be Map<String, dynamic> and the format of the json is different and can be changed, but want to know how to make it work with this format.

*** Edit

Working ListView

body: Column(
    children: <Widget>[
      Padding(
        padding: EdgeInsets.all(10.0),
        child: TextField(
          onChanged: (value) {
            ...
          },
          controller: _searchController,
          decoration: InputDecoration(

          ...
          ),
        ),
      ),
      Expanded(
        child: SizedBox(
          height: 200.0,
          child: ListView.builder(
              itemCount: list.length,
              itemBuilder: (BuildContext context, int index) {
                return Text(list[index].title);
              }),
        ),
      )
    ],
  ),
Ciprian
  • 3,066
  • 9
  • 62
  • 98

6 Answers6

33

The reason that print(json.decode(response.body).runtimeType) prints _InternalLinkedHashMap is because the top level of your json is indeed a map; {"results":[ opens with a brace.

So, json.decode(response.body) isn't a list and cannot be cast to one. On the other hand, json.decode(response.body)['results'] is a list.

You need:

  list = json.decode(response.body)['results']
      .map((data) => Model.fromJson(data))
      .toList();
Richard Heap
  • 48,344
  • 9
  • 130
  • 112
  • Hey, thank you for your answer. `print(list)` returns `[Instance of 'Model', Instance of 'Model', ...]` Is this correct? I can't seem to get the ListView working. Added that to the question as well. – Ciprian May 09 '19 at 06:49
  • 1
    That would need to be `list[index].title`. Your list is now correctly print that you have several models. Index indexes into the list, giving you one model, and you access the member variable by name with a dot. – Richard Heap May 09 '19 at 10:35
  • I'm sure I tried with dot, but I'll look again. Thanks – Ciprian May 09 '19 at 10:43
  • I edited my question showing the how I want to use the ListView widget. Flutter is returning this message: `flutter: Another exception was thrown: RenderBox was not laid out: RenderViewport#67a95 NEEDS-LAYOUT NEEDS-PAINT` – Ciprian May 09 '19 at 11:05
  • Found the answer here: https://stackoverflow.com/questions/52801201/flutter-renderbox-was-not-laid-out. Seems that the ListView widget needs to be wrapped by a a `SizedBox` – Ciprian May 09 '19 at 11:10
  • great! Try `Expanded` too as an alternative to sized box. – Richard Heap May 09 '19 at 11:14
  • I created a model class but nothing is called when trying to create the list. Is there a way to do this without creating a class? – Dekple Dec 04 '20 at 18:45
16

i tried like this and this worked

List<UserModel> users = (json.decode(response.body) as List)
      .map((data) => UserModel.fromJson(data))
      .toList();

My Json response is like :-

[{"id":4,"name":"1","email":"admin","password":"dc4b79a9200aa4630fee652bb5d7f232c503b77fb3b66df99b21ec3ff105f623","user_type":"1","created_on":"2020-01-13 12:50:28","updated_on":"2020-01-14 11:42:05","flags":"00000"},{"id":31,"name":"avi","email":"asdf@gmail.com","password":"dc4b79a9200aa4630fee652bb5d7f232c503b77fb3b66df99b21ec3ff105f623","user_type":"1","created_on":"2020-03-15 11:39:16","updated_on":"2020-03-15 11:39:16","flags":null}]
avinash
  • 501
  • 2
  • 8
  • 16
  • I created a model class but nothing is called when trying to create the list. Is there a way to do this without creating a class? – Dekple Dec 04 '20 at 18:45
5

The following was working for me:

List<Model>.from(
  json.decode(response.body)
  .map((data) => Model.fromJson(data))
)
Ruthinke
  • 83
  • 1
  • 4
1

For the list:

  List<ModelClass> modelList=<ModelClass>[];

  for (var json in result[HttpKeys.data]) {
    modelList.add(ModelClass.fromJson(json));
  }

The model class:

class ModelClass {
   ModelClass({
     this.id = '',
     this.title = '',
});

 String id;
 String title;

 factory ModelClass.fromJson(Map<String, dynamic> json) => ModelClass(
    id: json['_id'],
    title: json['title'],
  );

 Map<String, dynamic> toJson() => {
    '_id': id,
    'title': title,
  };
 }
hasan_iota
  • 21
  • 1
0

None of the above worked for me here is my solution.

 List<dynamic> jsonResponse = json.decode(response.body);
 List<ActiveOrderData> mReturnVal = [];
 jsonResponse.map((element) {mReturnVal.add(new ActiveOrderData.fromJson(element));}).toList();
Ole Pannier
  • 3,208
  • 9
  • 22
  • 33
-4

the following solve this code and work fine :

final response = await http.get("https://about.google/static/data/locations.json");

final data = jsonDecode(response.body)['offices'];