Converting map to list results in 'An error has occurred. Type _InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String'

Viewed 39

I'm getting the following returned from an api but it's type isn't allowing me to use it with a listview.builder. I've tried to convert it to List but I've been getting the following errors listed below that I can't resolve.

'An error has occurred. Type _InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String'

I re-worked my future response using (await json.decode(json.encode(results.data)) which resulted in the following error:

'FormatException: Unexpected character (at character 2) {id:1,name:john...

There's a carat pointing under ^ name

My decodedResults does indicate that it is indeed a List using the bottom code, so I'm not sure what is missing here.

Example returned data before manipulation from the api endpoint is of runtimeType _InternalLinkedHashMap<String, dynamic> as shown below when printed in the console

This is the response when printed from the Future

{id: 1, name: john, age: 32}
Details Class
    class Details {
        final String id;
        final String name;
        final String age;
    
        Details({
        required this.id,
        required this.name,
        required this.age
        })
    
        factory Details.fromJson(Map<String, dynamic> json) {
            return Details(
                id: json['id'] as String,
                name: json['name'] as String,
                age: json['age'] as String,
                
            );
        }
    } 

The Future that get's the example returned data from above

    Future<List<Details>> fetchDetails({required String id}) async {
        var results = await getData().get(id);
         var resultsString = results.data.toString();
        List<Details> list = [];
        List<Details> decodedResults = json.decode(resultsString);
        return resultsList;
      } 

Futurebuilder that calls the above fetchDetails that is returning the error

FutureBuilder<List<Details>>(
          future: fetchDetails().getData(id: id),
          builder: (context, snapshot) {
            if (snapshot.hasError) {
              return Center(
                child: Text(
                    'Error: ${snapshot.error}'),
              );
            } else if (snapshot.hasData) {
              return Flexible(child: DetailsList(details: snapshot.data!));
            } else {
              return const Center(
                child: CircularProgressIndicator(),
              );

Listview builder to display the results


class DetailsList extends StatefulWidget {
  const DetailsList({Key? key, required this.details}) : super(key: key);
  final List<Details> details;

  @override
  State<DetailsList> createState() => _DetailsListState();
}

class _DetailsListState extends State<DetailsList> {
  final ScrollController _scrollController = ScrollController();
 
  bool loading = false, allLoaded = false;

  @override
  void initState() {
    super.initState();
    _scrollController.addListener(() {
      if (_scrollController.position.pixels >=
          _scrollController.position.maxScrollExtent) {}
    });
  }

  @override
  void dispose() {
    super.dispose();
    _scrollController.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ListView.builder(
      controller: _scrollController,
      scrollDirection: Axis.vertical,
      itemCount: widget.details.length,
      itemBuilder: (context, index) {
        return Wrap(
          alignment: WrapAlignment.start,
          direction: Axis.horizontal,
          spacing: 1.0, 
          runSpacing: 1.0, 
          children: <Widget>[
            Container(
              child: Text("${widget.details[index].name}")
              ),
            ),
            Container(  
              child: Padding(
                padding: const EdgeInsets.only(top: 20),
                child: Text(
                    "${widget.details[index].age}"),
              ),
            ),
          ],
        );
      },
    );
  }
}
2 Answers

first thing what the response you got

if the response was one object like this

{id: 1, name: john, age: 32}

you can use this fun

 Future<Details> fetchDetails({required String id}) async {
    Response results = await getData().get(id);
    String resultsString = results.data;
    Details decodedResults = Details.fromJson(json.decode(resultsString));
    return decodedResults;
   }

or list of objects like this

[{id: 1, name: john, age: 32}]

you can use this fun

    Future<List<Details>> fetchDetails({required String id}) async {
       Response results = await getData().get(id);
       String resultsString = results.data;
       List<Details> decodedResults = (json.decode(resultsString) as 
       List).map((e) =>
            Details.fromJson(e)).toList();
  return decodedResults;
 }

in the next time when generate class form response json you can use package help you to convert map to class

The solution that wound up solving the issue in this case, after everyone's suggestions and help pointed to the creation of a list and add the response inside which solved the issue with a listview.builder needing a list and not map.

      Future<List<Details>> fetchDetails({required String id}) async {
        var results = await getData().get(id); 
        List<Details> newList = [Details.fromJson(results.data)];
        return newList;
        }
      } 
Related