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;
}
}