Reputation: 181
So i have a class AdsList which I want to use in future builder. I know I could have used a for loop and just stored the nested json in a list and use that in future builder, but I'm trying to use a class. in the fetchJson() method the variable parsed contains the json data and is not Null. I also commented out snapshot.length since I don't know how to return the length of the class AdsList.
I didn't paste entire file but the widget that doesn't build.
The nested json in the parsed variable has the format like this.
[
{
"id": 1,
"price": 1000000
},
{
"id": 2,
"price": 2000000
}
]
I'm a bit unsure what fetchJson() is supposed to return, or is not valid.
Future fetchJson() async {
Here is an image when the app is built.
It fails with this exception:
flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following NoSuchMethodError was thrown building:
flutter: Class 'AdsList' has no instance method '[]'.
flutter: Receiver: Instance of 'AdsList'
flutter: Tried calling: [](0)
Code
import 'package:flutter/foundation.dart'
show debugDefaultTargetPlatformOverride;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async'
show Future;
Future<dynamic> fetchJson() async {
String url = "http://<hidden_nested_json>";
final response = await http.get(url);
var parsed = json.decode(response.body);
AdsList ads = new AdsList.fromJson(parsed);
print(ads);
return ads;
}
class Ad {
final int id;
final int sqf;
final int price;
final String url;
//final String thumbnailUrl;
Ad({
this.id,
this.sqf,
this.price,
this.url
}) ;//, this.thumbnailUrl});
factory Ad.fromJson(Map<String, dynamic> json) {
return new Ad(
finnkode: json['id'] as int,
areal: json['sqf'] as int,
prisantydning: json['price'] as int,
url: json['url'] as String,
//thumbnailUrl: json['thumbnailUrl'] as String,
);
}
}
class AdsList {
final List<Ad> ads;
AdsList({
this.ads,
});
factory AdsList.fromJson(List<dynamic> parsedJson) {
List<Ad> ads = new List<Ad>();
ads = parsedJson.map((i)=>Ad.fromJson(i)).toList();
return new AdsList(
ads: ads,
);
}
}
class Houses extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new Scaffold(
body: Container(
child: FutureBuilder(
future: fetchJson(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
print(snapshot.data);
if (snapshot.data != null) {
return ListView.builder(
//itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: snapshot.data[index].id,
subtitle: snapshot.data[index].price,
);
}
);
}
},
),
)
);
}
}
Upvotes: 1
Views: 1673
Reputation: 4741
Your serialization is wrong! As you're passing the decoded .json which is a Map to your AdList.fromJson
constructor it must receive a Map<String,dynamic>
instance and not a List<dynamic>
.
I add a single key adList
in .json file just to be more clear.
"adList": [
{
"id": 1,
"price": 1000000
},
{
"id": 2,
"price": 2000000
}
]
In your AdList
constructor you should have:
factory AdsList.fromJson(Map<String, dynamic> json) {
// here we've a json map with a list "adList" of maps
// which holds your ads data.
var listOfMaps = List<Map<String,dynamic>>.from(json['adList']);
List<Ad> ads = new List<Ad>();
ads = listOfMaps.map(( adMap )=>Ad.fromJson( adMap )).toList();
return new AdsList(
ads: ads,
);
}
Now you don't need to change your fetch
method:
Future<dynamic> fetchJson() async {
String url = "http://<hidden_nested_json>";
final response = await http.get(url);
var parsed = json.decode(response.body);
AdsList ads = new AdsList.fromJson(Map.from(parsed));
print(ads);
return ads;
}
Take a look at this article to clear more your serialization skills. I hope it helps.
Upvotes: 1