Flutter: Expected a value of type 'Map<String, dynamic>', but got one of type 'List<dynamic>'

Viewed 1120

I am new to flutter, having the background of React and React Native. I am trying to fetch data from jsonplaceholder and want to return the json body on the screen, through a List. I have an ImageModel class for moedling the data on screen. This is my ImageModel class

class ImageModel {
  int id;
  String url;
  String title;

// Model class constructor
  ImageModel({this.id, this.url, this.title});

  ImageModel.fromJson(Map<String, dynamic> parsedJson) {
    id = parsedJson['id'];
    url = parsedJson['url'];
    title = parsedJson['title'];
  }
}

My ImageList component is as:

import 'package:flutter/material.dart';
import '../models/image_model.dart';

class ImageList extends StatelessWidget {
  final List<ImageModel> images;

  ImageList(this.images);

  @override
  Widget build(context) {
    return ListView.builder(
      itemCount: images.length,
      itemBuilder: (context, int index) {
        return Text(images[index].url);
      },
    );
  }
}

and my app component which renders all the data to main screen.

import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'models/image_model.dart';
import 'widgets/image_list.dart';

class MyApp extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return MyAppState();
  }
}

class MyAppState extends State<MyApp> {
  int counter = 0;
  List<ImageModel> images = [];

  fetchImage() async {
    var response = await http
        .get(Uri.parse('https://jsonplaceholder.typicode.com/photos'));
    var imagemodel = ImageModel.fromJson(jsonDecode(response.body));

    setState(() {
      images.add(imagemodel);
    });
  }

  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: ImageList(images),
        appBar: AppBar(
          title: Text("Let's See some Images!"),
        ),
        floatingActionButton: FloatingActionButton(
          child: Icon(Icons.add),
          onPressed: fetchImage,
        ),
      ),
      debugShowCheckedModeBanner: false,
    );
  }
}

and main.dart file

import 'package:flutter/material.dart';
import 'src/app.dart';

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

The debug console i get after pressing the ActionButton

Error: Expected a value of type 'Map<String, dynamic>', but got one of type 'List<dynamic>'
    at Object.throw_ [as throw] (http://localhost:58266/dart_sdk.js:5333:11)
    at Object.castError (http://localhost:58266/dart_sdk.js:5304:15)
    at Object.cast [as as] (http://localhost:58266/dart_sdk.js:5620:17)
    at dart.LegacyType.new.as (http://localhost:58266/dart_sdk.js:7218:60)
at app$.MyAppState.new.fetchImage (http://localhost:58266/packages/stephen_flutter/src/app.dart.lib.js:290:88)
    at fetchImage.next (<anonymous>)
    at http://localhost:58266/dart_sdk.js:39031:33
    at _RootZone.runUnary (http://localhost:58266/dart_sdk.js:38888:58)
    at _FutureListener.thenAwait.handleValue (http://localhost:58266/dart_sdk.js:33874:29)
    at handleValueCallback (http://localhost:58266/dart_sdk.js:34434:49)
    at Function._propagateToListeners (http://localhost:58266/dart_sdk.js:34472:17)
    at _Future.new.[_completeWithValue] (http://localhost:58266/dart_sdk.js:34314:23)
    at async._AsyncCallbackEntry.new.callback (http://localhost:58266/dart_sdk.js:34337:35)
    at Object._microtaskLoop (http://localhost:58266/dart_sdk.js:39175:13)
    at _startMicrotaskLoop (http://localhost:58266/dart_sdk.js:39181:13)
    at http://localhost:58266/dart_sdk.js:34688:9

After clicking the floatingActionButton i am directed to this file and at cursor moves to line 58 And why the execution stops as the Debug Control show (which i have underlined), Please click this link to see the screenshot

Anyone would love to help?

1 Answers

I think the problem is with fetchImage method. In JSON response you get a list of objects and in this method you are trying to create a single object from that list.

So you would need to convert that json into a list of ImageModels. You can achieve it using map method.

final decodedJson = jsonDecode(response.body) ;
final imageModels = decodedJson.map((image) => ImageModel.fromJson(image)).toList();

Then, when you want to add them to a list, use addAll method:

setState(() {
  images.addAll(imageModels);
});
Related