I take JSON data to Future<List<Data>> _DataList; with this method
and URL like https://nomer.biz.ua/mobile/kievstar?page=1
Future<List<Data>> getData(int pageCount) async {
String url = Uri.encodeFull("https://nomer.biz.ua/mobile/kievstar?page=$pageCount");
var response = await http.get(url, headers: {"Accept": "application/json"}).timeout(const Duration(seconds: 10));
final Map res = json.decode(response.body);
Response model = Response.fromJson(res);
page++;
return model.data;
}
And pass them to FutureBuilder
#override
Widget build(BuildContext context) {
return Scaffold(
body:FutureBuilder(
future: _DataList,
builder: (BuildContext ctx, AsyncSnapshot<dynamic> snapshot){
if (snapshot.connectionState != ConnectionState.done) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text("Error"));
}
if (!snapshot.hasData) {
return Center(child: Text("Error"));
}
var dataToShow = snapshot.data;
return ListView.builder(
controller: _controller,
itemCount: dataToShow == null ? 0 : dataToShow.length,
itemBuilder: (context, index) {
final item = dataToShow[index];
return Card(
//SHOW DATA
);
});
}
)
);
}
Invoke new page on
#override
void initState() {
_DataList = getData(page);
super.initState();
_controller.addListener(() {
if (_controller.position.pixels == _controller.position.maxScrollExtent) {
_DataList= getData(page);
}
});
}
The first page is displayed, but others are not processed. I load a new page, at the moment of scrolling the list to its last element. _DataList = getData(page); receives JSON data from 2 pages, but does not pass them to FutureBuilder.
I could not find a real example where url page navigation is implemented and FutureBuilder together.
You can copy paste run full code below
For demo purpose, I insert new page's data before old data to better see effect
Step 1: You can parse data to model Payload, you can see full code for detail
Step 2: Insert new data and return _DataList
Step 3: Define _future to avoid unnecessary rebuild
code snippet
Future<List<Datum>> getData(int pageCount) async {
String url =
Uri.encodeFull("https://nomer.biz.ua/mobile/kievstar?page=$pageCount");
var response = await http.get(url, headers: {
"Accept": "application/json"
}).timeout(const Duration(seconds: 10));
Payload payload = payloadFromJson(response.body);
_DataList.insertAll(0, payload.data);
page++;
return _DataList;
}
#override
void initState() {
_future = getData(page);
super.initState();
_controller.addListener(() {
if (_controller.position.pixels == _controller.position.maxScrollExtent) {
setState(() {
_future = getData(page);
});
}
});
}
FutureBuilder(
future: _future,
working demo
full code
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
Payload payloadFromJson(String str) => Payload.fromJson(json.decode(str));
String payloadToJson(Payload data) => json.encode(data.toJson());
class Payload {
Payload({
this.currentPage,
this.data,
this.firstPageUrl,
this.from,
this.lastPage,
this.lastPageUrl,
this.nextPageUrl,
this.path,
this.perPage,
this.prevPageUrl,
this.to,
this.total,
});
int currentPage;
List<Datum> data;
String firstPageUrl;
int from;
int lastPage;
String lastPageUrl;
String nextPageUrl;
String path;
int perPage;
dynamic prevPageUrl;
int to;
int total;
factory Payload.fromJson(Map<String, dynamic> json) => Payload(
currentPage: json["current_page"],
data: List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
firstPageUrl: json["first_page_url"],
from: json["from"],
lastPage: json["last_page"],
lastPageUrl: json["last_page_url"],
nextPageUrl: json["next_page_url"],
path: json["path"],
perPage: json["per_page"],
prevPageUrl: json["prev_page_url"],
to: json["to"],
total: json["total"],
);
Map<String, dynamic> toJson() => {
"current_page": currentPage,
"data": List<dynamic>.from(data.map((x) => x.toJson())),
"first_page_url": firstPageUrl,
"from": from,
"last_page": lastPage,
"last_page_url": lastPageUrl,
"next_page_url": nextPageUrl,
"path": path,
"per_page": perPage,
"prev_page_url": prevPageUrl,
"to": to,
"total": total,
};
}
class Datum {
Datum({
this.id,
this.nomerT,
this.datumOperator,
this.ourPrice,
});
int id;
String nomerT;
Operator datumOperator;
int ourPrice;
factory Datum.fromJson(Map<String, dynamic> json) => Datum(
id: json["id"],
nomerT: json["nomer_t"],
datumOperator: operatorValues.map[json["operator"]],
ourPrice: json["our_price"],
);
Map<String, dynamic> toJson() => {
"id": id,
"nomer_t": nomerT,
"operator": operatorValues.reverse[datumOperator],
"our_price": ourPrice,
};
}
enum Operator { KV }
final operatorValues = EnumValues({"kv": Operator.KV});
class EnumValues<T> {
Map<String, T> map;
Map<T, String> reverseMap;
EnumValues(this.map);
Map<T, String> get reverse {
if (reverseMap == null) {
reverseMap = map.map((k, v) => new MapEntry(v, k));
}
return reverseMap;
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int page = 1;
List<Datum> _DataList = [];
Future<List<Datum>> _future;
ScrollController _controller = ScrollController();
Future<List<Datum>> getData(int pageCount) async {
String url =
Uri.encodeFull("https://nomer.biz.ua/mobile/kievstar?page=$pageCount");
var response = await http.get(url, headers: {
"Accept": "application/json"
}).timeout(const Duration(seconds: 10));
Payload payload = payloadFromJson(response.body);
_DataList.insertAll(0, payload.data);
page++;
return _DataList;
}
#override
void initState() {
_future = getData(page);
super.initState();
_controller.addListener(() {
if (_controller.position.pixels == _controller.position.maxScrollExtent) {
setState(() {
_future = getData(page);
});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
future: _future,
builder: (BuildContext ctx, AsyncSnapshot<List<Datum>> snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.hasError) {
return Center(child: Text("Error"));
}
if (!snapshot.hasData) {
return Center(child: Text("Error"));
}
var dataToShow = snapshot.data;
return ListView.builder(
controller: _controller,
itemCount: dataToShow == null ? 0 : dataToShow.length,
itemBuilder: (context, index) {
final item = dataToShow[index];
return Card(
child: ListTile(
title: Text(dataToShow[index].id.toString()),
subtitle: Text(dataToShow[index].ourPrice.toString()),
),
);
});
}));
}
}
Related
When i run the application it doesnt fetch the data
import 'package:fakeapi/homepage.dart';
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:fakeapi/album.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.lightGreen,
),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
builder: ((context, snapshot) {
if (snapshot.hasError) {
throw Exception("ERROR");
} else if (snapshot.hasData) {
ListView.builder(
itemBuilder: ((context, index) {
return Text(snapshot.data!.title);
}),
itemCount: 1,
);
}
return Center(
child: CircularProgressIndicator(),
);
}),
future: getAlbums(),
),
);
}
}
Future<Album> getAlbums() async {
final response = await http
.get(Uri.parse("https://jsonplaceholder.typicode.com/albums/10"));
if (response.statusCode == 200) {
return Album.fromJson(jsonDecode(response.body));
} else {
throw Exception("hey");
}
}
// To parse this JSON data, do
//
// final album = albumFromJson(jsonString);
List<Album> albumFromJson(String str) =>
List<Album>.from(json.decode(str).map((x) => Album.fromJson(x)));
String albumToJson(List<Album> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
This is how i coded my class
class Album {
Album({
required this.userId,
required this.id,
required this.title,
});
int userId;
int id;
String title;
factory Album.fromJson(Map<String, dynamic> json) => Album(
userId: json["userId"],
id: json["id"],
title: json["title"],
);
Map<String, dynamic> toJson() => {
"userId": userId,
"id": id,
"title": title,
};
}
I tried to fetch data and display it
import 'package:fakeapi/homepage.dart';
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:fakeapi/album.dart';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/container.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.lightGreen,
),
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder(
builder: ((context, snapshot) {
if (snapshot.hasError) {
throw Exception("ERROR");
} else if (snapshot.hasData) {
ListView.builder(
itemBuilder: ((context, index) {
return Text(snapshot.data!.title);
}),
itemCount: 1,
);
}
return Center(
child: CircularProgressIndicator(),
);
}),
future: getAlbums(),
),
);
}
}
Future<Album> getAlbums() async {
final response = await http
.get(Uri.parse("https://jsonplaceholder.typicode.com/albums/10"));
if (response.statusCode == 200) {
return Album.fromJson(jsonDecode(response.body));
} else {
throw Exception("hey");
}
}
// To parse this JSON data, do
//
// final album = albumFromJson(jsonString);
List<Album> albumFromJson(String str) =>
List<Album>.from(json.decode(str).map((x) => Album.fromJson(x)));
String albumToJson(List<Album> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Album {
Album({
required this.userId,
required this.id,
required this.title,
});
int userId;
int id;
String title;
factory Album.fromJson(Map<String, dynamic> json) => Album(
userId: json["userId"],
id: json["id"],
title: json["title"],
);
Map<String, dynamic> toJson() => {
"userId": userId,
"id": id,
"title": title,
};
}
change your FutureBuilder to this:
builder: ((context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Center(
child: CircularProgressIndicator(),
);
default:
if (snapshot.hasError) {
throw Exception("ERROR");
} else {
return ListView.builder(
itemBuilder: ((context, index) {
return Text(snapshot.data!.title);
}),
itemCount: 1,
);
}
}
}),
How do you know it doesn't fetch the data? With your current code you always return the CircularProgressIndicator when there isn't an error.
You have to return the ListView builder. I.e.
return ListView.builder(
itemBuilder: ((context, index) {
return Text(snapshot.data!.title);
}),
itemCount: 1,
);
Your current api return a single model,
.....typicode.com/albums/10"
You wont get a list here. You can return single item from this like changing ListView to Text.
if (snapshot.hasData) {
return Text("${snapshot.data?.title}");
You can follow this widget to receive full list
class HomePage extends StatefulWidget {
const HomePage({super.key});
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
late final future = getAlbums();
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<List<Album>?>(
future: future,
builder: (context, snapshot) {
print(snapshot);
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data?.length,
itemBuilder: ((context, index) {
final model = snapshot.data![index];
return Text("${model.title}");
}),
);
}
return Center(
child: CircularProgressIndicator(),
);
}),
);
}
}
Future<List<Album>?> getAlbums() async {
final response =
await http.get(Uri.parse("https://jsonplaceholder.typicode.com/albums/"));
if (response.statusCode == 200) {
final data = jsonDecode(response.body) as List?;
return data?.map((e) => Album.fromJson(e)).toList();
} else {
throw Exception("hey");
}
}
I'm new to Flutter. On my HOME screen I have a ListView with fetched Json. I want to pass JSON variable ex:id on Tap to the next screen/class 'contantPage' to show another Json loaded from URL with id added.
ex.https:/example.com/myjson.php?id=1
Please! Show me the way.
main.dart
onTap: () {
Navigator.push(context,MaterialPageRoute(
builder(context)=>ContentPage(
photo: photos[index]
)),);},
And in my ContentPage.dart should add id value to URL as GET ex:?id=1
Future<Album> fetchAlbum() async {
// final query1 = Text(photo.publishDate);
final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums.php?id=I WANT ID HERE'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
class Album {
final int userId;
final int id;
final String title;
Album({
required this.userId,
required this.id,
required this.title,
});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
userId: json['userId'],
id: json['id'],
title: json['title'],
);
}
}
//void main() => runApp(MyApp());
class ContentPage extends StatefulWidget {
// ContentPage({Key? key, Photo photo}) : super(key: key);
ContentPage({Key? key, required Photo photo}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<ContentPage> {
late Future<Album> futureAlbum;
#override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Fetch Data Example'),
),
body: Center(
child: FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data!.title);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
),
),
);
}
}
Like the photo pass your photosid as follows:
onTap: () {
Navigator.push(context,MaterialPageRoute(
builder(context)=>ContentPage(
photo: photos[index],
id:photos[index].id,
)),);},
And then in ContentPage create constructor as follows:
class ContentPage extends StatefulWidget {
Photo photo;
String id;
ContentPage({Key? key, required this.photo,required this.id,}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
In initstate pass your id as follows:
#override
void initState() {
super.initState();
futureAlbum = fetchAlbum(widget.id);
}
And finally your fetchAlbum as follows:
Future<Album> fetchAlbum(var id) async {
// final query1 = Text(photo.publishDate);
final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums.php?id=id'));
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
I can't understand how to display more than 1 field with my code. I have title field and contentIntro field from Json and want to show all together.
body: Center(
child: FutureBuilder<Album>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Center(
child: Text(snapshot.data!.contentIntro),
//child: Text(snapshot.data!.Title),
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
),
I have a list of map in json and Im trying to render 'title' on a list.
Im reading data through through an api (http.get) then parse it.
I want to show the title in a list.
Here's my code...
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Getting the data
Future<Welcome> fetchAlbum() async {
final response = await http.get('https://jsonplaceholder.typicode.com/posts');
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Welcome.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
Convert to json
List<Welcome> welcomeFromJson(String str) =>
List<Welcome>.from(json.decode(str).map((x) => Welcome.fromJson(x)));
String welcomeToJson(List<Welcome> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
Model class Welcome
class Welcome {
Welcome({
this.userId,
this.id,
this.title,
this.body,
});
int userId;
int id;
String title;
String body;
factory Welcome.fromJson(Map<String, dynamic> json) => Welcome(
userId: json["userId"],
id: json["id"],
title: json["title"],
body: json["body"],
);
Map<String, dynamic> toJson() => {
"userId": userId,
"id": id,
"title": title,
"body": body,
};
}
void main() {
runApp(MyApp());
}
class MyApp extends StatefulWidget {
MyApp({Key key}) : super(key: key);
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Future<Welcome> futureAlbum;
#override
void initState() {
super.initState();
futureAlbum = fetchAlbum();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fetch Data Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text('Fetch Data Example'),
),
body: Center(
child: FutureBuilder<Welcome>(
future: futureAlbum,
builder: (context, snapshot) {
if (snapshot.hasData) {
return new Text(snapshot.data.title);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
),
),
);
}
}
Im getting an error saying " type 'List' is not a subtype of type 'Map<String, dynamic>' "
Change your fetchAlbum function to this
Future<List<Welcome>> fetchAlbum() async {
final response =
await http.get('https://jsonplaceholder.typicode.com/posts');
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
// return Welcome.fromJson(jsonDecode(response.body));
var jsonData = jsonDecode(response.body);
List<Welcome> welcome = [];
for (var v in jsonData) {
Welcome w1 = Welcome(
userId: v['userId'],
id: v['id'],
title: v['title'],
body: v['body']);
welcome.add(w1);
}
return welcome;
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
The FutureBuider widget will be this
child: FutureBuilder(
future: fetchAlbum(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Container(
margin: EdgeInsets.all(8),
child: Column(
children: [
Text("User Id = ${snapshot.data[index].userId}"),
Text("Id = ${snapshot.data[index].id}"),
Text("Title = ${snapshot.data[index].title}"),
Text("Body = ${snapshot.data[index].body}"),
],
),
);
});
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return CircularProgressIndicator();
},
),
Dart / Flutter JSON parsing and display
I am having trouble parsing and displaying the info. Am getting data from API
I get a response == 200 from API but am unable to display it.
The printout on screen is "Instance of medData"
Future<medData> fetchData(http.Client client) async {
final response = await http.get(
'xxxxxxxxxx',
headers: {
"host": "rapidapi.com",
"key": "x87439756734",
},
);
if (response.statusCode == 200) {
// List json = json.decode(response.body);
// return json.map((medData) => new medData.fromJson(medData)).toList();
return medData.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load data from API');
}
}
This Is the List View Builder
ListView _medDataListView(data) {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return _tile(data[index].cases, data[index].number, Icons.work);
});
}
Tile builder
ListTile _tile(String title, String subtitle, IconData icon) => ListTile(
title: Text(title,
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 20,
)),
subtitle: Text(subtitle),
leading: Icon(
icon,
color: Colors.blue[500],
),
);
Class medData for parsing the JSON
class medData {
String country;
List<LatestStatByCountry> latestStatByCountry;
medData({this.country, this.latestStatByCountry});
medData.fromJson(Map<String, dynamic> json) {
country = json['country'];
if (json['latest_stat_by_country'] != null) {
latestStatByCountry = new List<LatestStatByCountry>();
json['latest_stat_by_country'].forEach((v) {
latestStatByCountry.add(new LatestStatByCountry.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['country'] = this.country;
if (this.latestStatByCountry != null) {
data['latest_stat_by_country'] =
this.latestStatByCountry.map((v) => v.toJson()).toList();
}
return data;
}
}
class LatestStatByCountry {
String id;
String countryName;
String totalCases;
String newCases;
String activeCases;
String totalDeaths;
String newDeaths;
String totalRecovered;
String seriousCritical;
Null region;
String totalCasesPer1m;
String recordDate;
LatestStatByCountry(
{this.id,
this.countryName,
this.totalCases,
this.newCases,
this.activeCases,
this.totalDeaths,
this.newDeaths,
this.totalRecovered,
this.seriousCritical,
this.region,
this.totalCasesPer1m,
this.recordDate});
LatestStatByCountry.fromJson(Map<String, dynamic> json) {
id = json['id'];
countryName = json['country_name'];
totalCases = json['total_cases'];
newCases = json['new_cases'];
activeCases = json['active_cases'];
totalDeaths = json['total_deaths'];
newDeaths = json['new_deaths'];
totalRecovered = json['total_recovered'];
seriousCritical = json['serious_critical'];
region = json['region'];
totalCasesPer1m = json['total_cases_per1m'];
recordDate = json['record_date'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['country_name'] = this.countryName;
data['total_cases'] = this.totalCases;
data['new_cases'] = this.newCases;
data['active_cases'] = this.activeCases;
data['total_deaths'] = this.totalDeaths;
data['new_deaths'] = this.newDeaths;
data['total_recovered'] = this.totalRecovered;
data['serious_critical'] = this.seriousCritical;
data['region'] = this.region;
data['total_cases_per1m'] = this.totalCasesPer1m;
data['record_date'] = this.recordDate;
return data;
}
}
Building the widget
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FutureBuilder<medData>(
future: fetchData(http.Client()),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text("${snapshot.data}");
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
),
),
);
}
}
I don't really know what i'm doing wrong when trying to display the data.
You can copy paste run full code below
Step 1 : parse json string with medDataFromJson(response.body);
factory MedData.fromJson(Map<String, dynamic> json) => MedData(
country: json["country"],
latestStatByCountry: List<LatestStatByCountry>.from(
json["latest_stat_by_country"]
.map((x) => LatestStatByCountry.fromJson(x))),
);
Step 2 : In FutureBuilder do return _medDataListView(snapshot.data.latestStatByCountry);
Step 3: ListView _medDataListView(List<LatestStatByCountry> data) data is List<LatestStatByCountry>
working demo
full code
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
// To parse this JSON data, do
//
// final medData = medDataFromJson(jsonString);
import 'dart:convert';
MedData medDataFromJson(String str) => MedData.fromJson(json.decode(str));
String medDataToJson(MedData data) => json.encode(data.toJson());
class MedData {
String country;
List<LatestStatByCountry> latestStatByCountry;
MedData({
this.country,
this.latestStatByCountry,
});
factory MedData.fromJson(Map<String, dynamic> json) => MedData(
country: json["country"],
latestStatByCountry: List<LatestStatByCountry>.from(
json["latest_stat_by_country"]
.map((x) => LatestStatByCountry.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"country": country,
"latest_stat_by_country":
List<dynamic>.from(latestStatByCountry.map((x) => x.toJson())),
};
}
class LatestStatByCountry {
String id;
String countryName;
String totalCases;
String newCases;
String activeCases;
String totalDeaths;
String newDeaths;
String totalRecovered;
String seriousCritical;
dynamic region;
String totalCasesPer1M;
DateTime recordDate;
LatestStatByCountry({
this.id,
this.countryName,
this.totalCases,
this.newCases,
this.activeCases,
this.totalDeaths,
this.newDeaths,
this.totalRecovered,
this.seriousCritical,
this.region,
this.totalCasesPer1M,
this.recordDate,
});
factory LatestStatByCountry.fromJson(Map<String, dynamic> json) =>
LatestStatByCountry(
id: json["id"],
countryName: json["country_name"],
totalCases: json["total_cases"],
newCases: json["new_cases"],
activeCases: json["active_cases"],
totalDeaths: json["total_deaths"],
newDeaths: json["new_deaths"],
totalRecovered: json["total_recovered"],
seriousCritical: json["serious_critical"],
region: json["region"],
totalCasesPer1M: json["total_cases_per1m"],
recordDate: DateTime.parse(json["record_date"]),
);
Map<String, dynamic> toJson() => {
"id": id,
"country_name": countryName,
"total_cases": totalCases,
"new_cases": newCases,
"active_cases": activeCases,
"total_deaths": totalDeaths,
"new_deaths": newDeaths,
"total_recovered": totalRecovered,
"serious_critical": seriousCritical,
"region": region,
"total_cases_per1m": totalCasesPer1M,
"record_date": recordDate.toIso8601String(),
};
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
MedData medData;
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
ListView _medDataListView(List<LatestStatByCountry> data) {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return _tile(
data[index].countryName, data[index].totalCases, Icons.work);
});
}
ListTile _tile(String title, String subtitle, IconData icon) => ListTile(
title: Text(title,
style: TextStyle(
fontWeight: FontWeight.w500,
fontSize: 20,
)),
subtitle: Text(subtitle),
leading: Icon(
icon,
color: Colors.blue[500],
),
);
Future<MedData> fetchData(http.Client client) async {
final response = await http.get(
'https://coronavirus-monitor.p.rapidapi.com/coronavirus/latest_stat_by_country.php?country=South%20Africa',
headers: {
"x-rapidapi-host": "coronavirus-monitor.p.rapidapi.com",
"x-rapidapi-key": "23bdb74dbfmsh865510b645e32f6p1f7b7bjsn2e800c1ac844",
},
);
/*String jsonString = '''
{ "country": "South Africa", "latest_stat_by_country": [ { "id": "216413", "country_name": "South Africa", "total_cases": "709", "new_cases": "", "active_cases": "697", "total_deaths": "", "new_deaths": "", "total_recovered": "12", "serious_critical": "2", "region": null, "total_cases_per1m": "12", "record_date": "2020-03-26 05:50:02.171" } ] }
''';
http.Response response = http.Response(jsonString, 200);*/
if (response.statusCode == 200) {
// List json = json.decode(response.body);
// return json.map((medData) => new medData.fromJson(medData)).toList();
//return medData.fromJson(json.decode(response.body));
medData = medDataFromJson(response.body);
return medData;
} else {
throw Exception('Failed to load data from API');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FutureBuilder<MedData>(
future: fetchData(http.Client()),
builder: (context, snapshot) {
if (snapshot.hasData) {
//return Text("${snapshot.data}");
return _medDataListView(snapshot.data.latestStatByCountry);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
},
),
),
);
}
}
I'd like to be able to return my profileList to my ListView in alphabetical order.
I have my "All people" class which has a ListView widget using the json and creating a list of people.
The code below is from my All People class where I'm fetching the json.
class AllPeople extends StatefulWidget {
final String title;
AllPeople(this.title);
#override
AllPeopleState createState() => AllPeopleState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Listviews"),
),
);
}
class AllPeopleState extends State<AllPeople> {
List data;
List<Profile> profiles;
Future<String> getData() async {
var response = await http.get(
Uri.encodeFull("http://test.mallcomm.co.uk/json_feeds/users.json"),
headers: {"Accept": "application/json"});
fetchPeople().then((List<Profile> p) {
this.setState(() {
data = json.decode(response.body);
profiles = p;
});
});
return "Success!";
}
#override
void initState() {
this.getData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('CMS Users'),
),
body: ListView.builder(
padding: EdgeInsets.only(top: 20.0, left: 4.0),
itemExtent: 70.0,
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, int index) {
return Card(
elevation: 10.0,
child: InkWell(
onTap: () {
Navigator.push(
context,
new MaterialPageRoute(
builder: (BuildContext context) =>
new PeopleDetails("Profile Page", profiles[index]),
));
},
child: ListTile(
leading: CircleAvatar(
child: Text(profiles[index].getInitials()),
backgroundColor: Colors.deepPurple,
radius: 30.0,
),
title: Text(
data[index]["firstname"] + "." + data[index]["lastname"]),
subtitle: Text(
data[index]["email"] + "\n" + data[index]["phonenumber"]),
),
),
);
}),
);
}
}
Future<List<Profile>> fetchPeople() async {
try {
http.Response response =
await http.get('http://test.mallcomm.co.uk/json_feeds/users.json');
List<dynamic> responseJson = json.decode(response.body);
List<Profile> profileList =
responseJson.map((d) => new Profile.fromJson(d)).toList();
profileList.sort((a, b) {
return a.lastName.toLowerCase().compareTo(b.lastName.toLowerCase());
});
return profileList;
} catch (e) {
print(e.toString());
}
return null;
}
I then have my "User profile" class which is storing my json Profile
class Profile {
final String firstName;
final String lastName;
final String phoneNumber;
final String userEmail;
bool verifiedValue = false;
bool approvedValue = false;
bool securityApprovedValue = false;
bool blockedValue = false;
Profile({this.firstName, this.lastName, this.phoneNumber, this.userEmail});
factory Profile.fromJson(Map<String, dynamic> json) {
return new Profile(
firstName: json["firstname"],
lastName: json["lastname"],
phoneNumber: json["phonenumber"],
userEmail: json["email"],
);
}
I've tried to do something like
profileList.sort((a,b) {
return a.lastName.toLowerCase().compareTo(b.lastName.toLowerCase());
});
just before I return profileList but it didn't work. I've tried looking at some different examples but If i'm honest I don't understand it too well.
The sort function you suggested does seem to work as you'd expect (but, of course, only compares last name - you might want to compare first name if the last names are equal). I tidied up a bit, to produce this working example:
import 'dart:convert';
import 'dart:async';
import 'package:http/http.dart' as http;
main() async {
fetchPeople().then((list) {
list.forEach(print);
});
}
Future<List<Profile>> fetchPeople() async {
try {
http.Response response =
await http.get('http://test.mallcomm.co.uk/json_feeds/users.json');
List<dynamic> responseJson = json.decode(response.body);
List<Profile> profileList =
responseJson.map((d) => new Profile.fromJson(d)).toList();
profileList.sort((a, b) {
return a.lastName.toLowerCase().compareTo(b.lastName.toLowerCase());
});
return profileList;
} catch (e) {
print(e.toString());
}
}
class Profile {
final String firstName;
final String lastName;
final String phoneNumber;
final String userEmail;
bool verifiedValue = false;
bool approvedValue = false;
bool securityApprovedValue = false;
bool blockedValue = false;
Profile({this.firstName, this.lastName, this.phoneNumber, this.userEmail});
factory Profile.fromJson(Map<String, dynamic> json) {
return new Profile(
firstName: json["firstname"],
lastName: json["lastname"],
phoneNumber: json["phonenumber"],
userEmail: json["email"],
);
}
#override
String toString() {
return 'Profile: $firstName $lastName';
}
}
Here's a State example that works.
class _MyHomePageState extends State<MyHomePage> {
List<Profile> profiles = [];
#override
void initState() {
super.initState();
_refresh();
}
void _refresh() {
fetchPeople().then((list) {
setState(() {
profiles = list;
});
});
}
Future<List<Profile>> fetchPeople() async {
try {
http.Response response =
await http.get('http://test.mallcomm.co.uk/json_feeds/users.json');
List<dynamic> responseJson = json.decode(response.body);
List<Profile> profileList =
responseJson.map((d) => new Profile.fromJson(d)).toList();
profileList.sort((a, b) {
return a.lastName.toLowerCase().compareTo(b.lastName.toLowerCase());
});
return profileList;
} catch (e) {
print(e.toString());
return [];
}
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: new ListView.builder(
itemBuilder: (context, i) => new Text('${profiles[i].firstName} ${profiles[i].lastName}'),
itemCount: profiles.length,
),
);
}
}