Home > database >  Converting map to list results in 'An error has occurred. Type _InternalLinkedHashMap<String
Converting map to list results in 'An error has occurred. Type _InternalLinkedHashMap<String

Time:09-09

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}"),
              ),
            ),
          ],
        );
      },
    );
  }
}

CodePudding user response:

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

CodePudding user response:

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