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();
},
),
),
);
}
}
Related
Would you be able to help me a bit as I am struggling with a conversion of API response into JSON/Object and then into DataTable.
I have a Stateful widget where I am getting data during Init:
class _AlertState extends State<Alert> {
final Api _api_service = Api();
late Future<List<Data>> _watchdog;
#override
void initState() {
_watchdog = _api_service.get_watchdog();
super.initState();
}
get_watchdog()
Future<List<Data>> get_watchdog() async {
var data = utf8.encode('{xxx}');
Response raw_response = await post(url, headers: headers, body: data);
if (raw_response.statusCode == 200) {
var res_json = jsonDecode(raw_response.body);
Watchdog watchdog = Watchdog.fromJson(res_json);
return watchdog.result!.data!;
} else{
Api.error_message = raw_response.statusCode as String;
throw Exception('xxx');
}
}
Watchdog object
class Watchdog {
String? version;
Error? error;
Result? result;
Watchdog({this.version, this.error, this.result});
Watchdog.fromJson(Map<String, dynamic> json) {
version = json['version'];
result = json['error'] != null ? new Result.fromJson(json['error']) : null;
result = json['result'] != null ? new Result.fromJson(json['result']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['version'] = this.version;
if (this.result != null) {
data['result'] = this.result!.toJson();
}
if (this.error != null) {
data['error'] = this.result!.toJson();
}
return data;
}
}
class Result {
String? now;
List<Data>? data;
Result({this.now, this.data});
Result.fromJson(Map<String, dynamic> json) {
now = json['now'];
if (json['data'] != null) {
data = <Data>[];
json['data'].forEach((v) {
data!.add(new Data.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['now'] = this.now;
if (this.data != null) {
data['data'] = this.data!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Data {
String? status;
String? problemtype;
String? message;
Data({this.status, this.problemtype, this.message});
Data.fromJson(Map<String, dynamic> json) {
status = json['status'];
problemtype = json['problemtype'];
message = json['message'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
data['problemtype'] = this.problemtype;
data['message'] = this.message;
return data;
}
#override
String toString() {
return "Data(status: $status, problemtype: $problemtype, message: $message)";
}
}
class Error {
int? code;
String? message;
String? name;
Error({this.code, this.message, this.name});
Error.fromJson(Map<String, dynamic> json) {
code = json['code'];
message = json['message'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['code'] = this.code;
data['message'] = this.message;
data['name'] = this.name;
return data;
}
}
Can you please point me how to convert now the returned Future into Datatable when I press the button?
Widget build(BuildContext context) {
return Column(
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
columns: <DataColumn>[
DataColumn(
label: Text('Status'),
),
DataColumn(
label: Text('Description'),
),
],
// rows: ???
),
),
TextButton(
onPressed: () {
if (_watchdog != null){
_watchdog.
} else{
print('empty');
}
},
child: Text('print'),
)
],
);
}
Thanks.
Can you please point me how to convert now the returned Future into Datatable when I press the button
=>you want to get data from API after clicking on the button, right ?
Solution ^^
In this case , you can't use a FutureBuilder Widget. Therefore ,include the last code in the stateful widget then you may simply use setState
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List<Data>? _watchdogs; // ---> remove Future
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Center(
child: Column(
children: [
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Visibility(
visible: _watchdogs!=null,
child: DataTable(
columns: <DataColumn>[
DataColumn(
label: Text('Status'),
),
DataColumn(
label: Text('Description'),
),
], rows: _watchdogs!.map((_watchdog) =>
DataRow(cells: [
//example
DataCell(Text(${_watchdog.name})),
DataCell(Text(${_watchdog.type})),
])
).toList(),
),
)
),
ElevatedButton(
onPressed: () async{
if (_watchdogs != null){
//get data from API, not forget to add async and await here
List<Data> data =await _api_service.get_watchdog();
setState(() {
_watchdogs=data;
});
} else{
print('empty');
}
},
child: Text('print'),
)
],
),
),
),
);
}
}
I have trouble with requesting Public Api and convert Json format to Dart object. I have try every solution available on google, but it still doesn't work.
When I try to run, the "object_patch.dart" file always said:
#patch
#pragma("vm:entry-point", "call")
dynamic noSuchMethod(Invocation invocation) {
// TODO(regis): Remove temp constructor identifier 'withInvocation'.
throw new NoSuchMethodError.withInvocation(this, invocation);
}
This is how i convert Json to Dart object:
class Movie {
List<Search> search;
Movie({this.search});
static Movie fromJson(Map<String, dynamic> json) {
return Movie(search: List<Search>.from(json['Search']));
}
}
class Search {
final String imdbID;
final String title;
final String year;
final String poster;
Search({this.imdbID, this.title, this.year, this.poster});
static Search fromJson(Map<String, dynamic> json) {
return Search(
imdbID: json['imdbID'],
title: json['Title'],
year: json['Year'],
poster: json['Poster'],
);
}
}
This is how i perform http request :
Future<List<Movie>> fetchMovie() async {
final response = await http
.get('https://fake-movie-database-api.herokuapp.com/api?s=batman');
final body = jsonDecode(response.body).cast<Map<String, dynamic>>();
return body.map<Movie>((json) => Movie.fromJson(json)).toList();
}
This is my FutureBuilder :
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
Widget build(BuildContext context) {
return FutureBuilder<List<Movie>>(
future: fetchMovie(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: 5,
itemBuilder: (context, index) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 25, vertical: 16),
height: 200,
color: Colors.blue,
child: Center(
child: Text(snapshot.data[index].search[index].title),
),
);
});
}
return CircularProgressIndicator();
});
}
}
This is my Rest Api from https://fake-movie-database-api.herokuapp.com/
{"Search":
[
{
"imdbID":"tt0096895",
"Title":"Batman",
"Year":"1989",
"Poster":"https://images-na.ssl-images-amazon.com/images/M/MV5BMTYwNjAyODIyMF5BMl5BanBnXkFtZTYwNDMwMDk2._V1_.jpg"
},
{
"imdbID":"tt0468569",
"Title":"The Dark Knight",
"Year":"2008",
"Poster":"https://ia.media-imdb.com/images/M/MV5BMTMxNTMwODM0NF5BMl5BanBnXkFtZTcwODAyMTk2Mw##._V1_UX182_CR0,0,182,268_AL_.jpg"
},
{
"imdbID":"tt2975590",
"Title":"Batman v Superman: Dawn of Justice",
"Year":"2016",
"Poster":"https://ia.media-imdb.com/images/M/MV5BYThjYzcyYzItNTVjNy00NDk0LTgwMWQtYjMwNmNlNWJhMzMyXkEyXkFqcGdeQXVyMTQxNzMzNDI#._V1_UX182_CR0,0,182,268_AL_.jpg"
},
{
"imdbID":"tt1345836",
"Title":"The Dark Knight Rises",
"Year":"2012",
"Poster":"https://ia.media-imdb.com/images/M/MV5BMTk4ODQzNDY3Ml5BMl5BanBnXkFtZTcwODA0NTM4Nw##._V1_UX182_CR0,0,182,268_AL_.jpg"},
{
"imdbID":"tt0372784",
"Title":"Batman Begins",
"Year":"2005",
"Poster":"https://ia.media-imdb.com/images/M/MV5BYzc4ODgyZmYtMGFkZC00NGQyLWJiMDItMmFmNjJiZjcxYzVmXkEyXkFqcGdeQXVyNDYyMDk5MTU#._V1_UX182_CR0,0,182,268_AL_.jpg"
},
{
"imdbID":"tt4116284",
"Title":"The LEGO Batman Movie",
"Year":"2017",
"Poster":"https://ia.media-imdb.com/images/M/MV5BMTcyNTEyOTY0M15BMl5BanBnXkFtZTgwOTAyNzU3MDI#._V1_UX182_CR0,0,182,268_AL_.jpg"
},
{
"imdbID":"tt0112462",
"Title":"Batman Forever",
"Year":"1995",
"Poster":"https://ia.media-imdb.com/images/M/MV5BNWY3M2I0YzItNzA1ZS00MzE3LThlYTEtMTg2YjNiOTYzODQ1XkEyXkFqcGdeQXVyMTQxNzMzNDI#._V1_UX182_CR0,0,182,268_AL_.jpg"},
{
"imdbID":"tt0118688",
"Title":"Batman & Robin",
"Year":"1997",
"Poster":"https://ia.media-imdb.com/images/M/MV5BMGQ5YTM1NmMtYmIxYy00N2VmLWJhZTYtN2EwYTY3MWFhOTczXkEyXkFqcGdeQXVyNTA2NTI0MTY#._V1_UX182_CR0,0,182,268_AL_.jpg"
},
{
"imdbID":"tt0103776",
"Title":"Batman Returns",
"Year":"1992",
"Poster":"https://ia.media-imdb.com/images/M/MV5BOGZmYzVkMmItM2NiOS00MDI3LWI4ZWQtMTg0YWZkODRkMmViXkEyXkFqcGdeQXVyODY0NzcxNw##._V1_UX182_CR0,0,182,268_AL_.jpg"
}
]
}
This is working for me.
Model Class
import 'dart:convert';
Movie movieFromJson(String str) => Movie.fromJson(json.decode(str));
String movieToJson(Movie data) => json.encode(data.toJson());
class Movie {
Movie({
this.search,
});
List<Search> search;
factory Movie.fromJson(Map<String, dynamic> json) => Movie(
search: json["Search"] == null ? null : List<Search>.from(json["Search"].map((x) => Search.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"Search": search == null ? null : List<dynamic>.from(search.map((x) => x.toJson())),
};
}
class Search {
Search({
this.imdbId,
this.title,
this.year,
this.poster,
});
String imdbId;
String title;
String year;
String poster;
factory Search.fromJson(Map<String, dynamic> json) => Search(
imdbId: json["imdbID"] == null ? null : json["imdbID"],
title: json["Title"] == null ? null : json["Title"],
year: json["Year"] == null ? null : json["Year"],
poster: json["Poster"] == null ? null : json["Poster"],
);
Map<String, dynamic> toJson() => {
"imdbID": imdbId == null ? null : imdbId,
"Title": title == null ? null : title,
"Year": year == null ? null : year,
"Poster": poster == null ? null : poster,
};
}
HTTP Call
Future<Movie> fetchMovie() async {
try {
final response = await http
.get('https://fake-movie-database-api.herokuapp.com/api?s=batman');
Map dataMap = jsonDecode(response.body);
var movies = Movie.fromJson(dataMap);
return movies;
} catch (e) {
print(e);
return null;
}
}
Problems in your code:
Your fetchMovie is returning a Future<Movie> and not a Future<List<Movie>>
In your HomePage, you use the index twice in Text(snapshot.data[index].search[index].title)
I would also suggest using only one class for your model instead of two.
Here is my solution:
Full source code
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:http/http.dart' as http;
part '66419469.json.freezed.dart';
part '66419469.json.g.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
home: HomePage(),
),
);
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Future<List<Movie>> fetchMovies() async {
final response = await http
.get('https://fake-movie-database-api.herokuapp.com/api?s=batman');
final jsonData = jsonDecode(response.body)['Search'];
final result =
jsonData.map<Movie>((jsonMovie) => Movie.fromJson(jsonMovie)).toList();
return result;
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<List<Movie>>(
future: fetchMovies(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: 5,
itemBuilder: (context, index) {
final movie = snapshot.data[index];
return ListTile(
leading: Image.network('${movie.poster}', height: 128.0),
title: Text(movie.title),
subtitle: Text('${movie.year}, ${movie.imdbID}'),
);
},
);
} else if (snapshot.hasError) {
return Text('ERROR: ${snapshot.error}');
} else {
return Text('No movie found.');
}
}
return CircularProgressIndicator();
},
),
);
}
}
#freezed
abstract class Movie with _$Movie {
factory Movie({
String imdbID,
#JsonKey(name: 'Title') String title,
#JsonKey(name: 'Year') String year,
#JsonKey(name: 'Poster') String poster,
}) = _Movie;
factory Movie.fromJson(Map<String, dynamic> json) => _$MovieFromJson(json);
}
Note, I used freezed package to generate the code for my Movie Model, including the from/toJson functionality.
I am using an API,to fetch data and display it in a list view after some constraints.I am fetching the data from the API ,it is printing as well and getting stored as well.But still I am getting Unhandled Exception: DatabaseException(datatype mismatch),though I checked the order in which I have put them down in correct.I am really fed up with this JSON parsing.It is a real pain actually speaking.
Below is the list of dart files I have used in my flutter project:
This is my main file,where I will be displaying the data in a list view:
import 'package:flutter/material.dart';
import 'services.dart';
import 'db_provider.dart';
void main() => runApp(Main());
class Main extends StatefulWidget {
#override
_MainState createState() => _MainState();
}
class _MainState extends State<Main> {
var isLoading = false;
_loadFromApi() async {
setState(() {
isLoading = true;
});
var apiProvider = Services();
await apiProvider.getAllCustomers();
// wait for 2 seconds to simulate loading of data
await Future.delayed(const Duration(seconds: 2));
setState(() {
isLoading = false;
});
}
Widget _buildEmployeeListView() {
return FutureBuilder(
future: DBProvider.db.getAllCustomers(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (!snapshot.hasData) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return ListView.separated(
separatorBuilder: (context, index) =>
Divider(
color: Colors.black12,
),
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: Text(
"${index + 1}",
style: TextStyle(fontSize: 20.0),
),
title: Text(
"Name: ${snapshot.data[index].name} "),
subtitle: Text('status: ${snapshot.data[index].status}'),
);
},
);
}
},
);
}
#override
void initState() {
super.initState();
_loadFromApi();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Customer details'),
),
body: _buildEmployeeListView(),
),
);
}
}
Below is my JSON data:
{
"list":[
{
"id":"MnJJA0dbuw",
"name":"Anand Sharma",
"img":"https://incablet-tests.s3.ap-south-1.amazonaws.com/conference-content/photos/sponsors/Anand.jpeg",
"gender":"m",
"age":46,
"date":"23/11/2019",
"status":"onboarded"
},
{
"id":"MnZmmmbuw",
"name":"Malashri Lal",
"img":"https://incablet-tests.s3.ap-south-1.amazonaws.com/conference-content/photos/sponsors/Vishesh.jpg",
"gender":"f",
"age":70,
"date":"01/10/2019",
"status":"active"
},
{
"id":"MnZy10dpsq",
"name":"Suhasini Haidar",
"img":"https://incablet-tests.s3.ap-south-1.amazonaws.com/conference-content/photos/sponsors/Suhasini.jpg",
"gender":"f",
"age":30,
"date":"23/03/2019",
"status":"left"
},
{
"id":"HOnmFt5jA",
"name":"Vishesh Mahajan",
"img":"https://incablet-tests.s3.ap-south-1.amazonaws.com/conference-content/photos/sponsors/Vishesh.jpg",
"gender":"m",
"age":34,
"date":"05/05/2019",
"status":"active"
},
{
"id":"MnZy10dxyz",
"name":"Anand Neelakantan",
"img":"https://incablet-tests.s3.ap-south-1.amazonaws.com/conference-content/photos/sponsors/Anand.jpeg",
"gender":"m",
"age":46,
"date":"03/10/2019",
"status":"left"
},
{
"id":"MnZy1JJbuw",
"name":"Malashri",
"img":"https://incablet-tests.s3.ap-south-1.amazonaws.com/conference-content/photos/sponsors/Malashri.jpg",
"gender":"f",
"age":65,
"date":"04/01/2019",
"status":"active"
},
{
"id":"JKAS10dbuw",
"name":"Meenakshi Madhavan",
"img":"https://incablet-tests.s3.ap-south-1.amazonaws.com/conference-content/photos/sponsors/Meenakshi.jpg",
"gender":"f",
"age":35,
"date":"01/03/2020",
"status":"left"
},
{
"id":"sOw8c6BOug",
"name":"Fintan",
"img":"https://incablet-tests.s3.ap-south-1.amazonaws.com/conference-content/photos/sponsors/Fintan.jpg",
"gender":"m",
"age":55,
"date":"09/12/2019",
"status":"onboarded"
},
{
"id":"MnZy10dlll",
"name":"Jaishree Periwal",
"img":"https://incablet-tests.s3.ap-south-1.amazonaws.com/conference-content/photos/sponsors/Jaishree.jpg",
"gender":"f",
"age":50,
"date":"01/02/2020",
"status":"active"
},
{
"id":"KbN3VELflA",
"name":"Anukriti Upadhyay",
"img":"https://incablet-tests.s3.ap-south-1.amazonaws.com/conference-content/photos/sponsors/Anukriti.jpg",
"gender":"f",
"age":30,
"date":"31/01/2020",
"status":"onboarded"
}
]
}
Below is the PODO file I have created:
// To parse this JSON data, do
//
// final customerInfo = customerInfoFromJson(jsonString);
import 'dart:convert';
CustomerInfo customerInfoFromJson(String str) => CustomerInfo.fromJson(json.decode(str));
String customerInfoToJson(CustomerInfo data) => json.encode(data.toJson());
class CustomerInfo {
CustomerInfo({
this.list,
});
List<ListElement> list;
factory CustomerInfo.fromJson(Map<String, dynamic> json) => CustomerInfo(
list: List<ListElement>.from(json["list"].map((x) => ListElement.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"list": List<dynamic>.from(list.map((x) => x.toJson())),
};
}
class ListElement {
ListElement({
this.id,
this.name,
this.img,
this.gender,
this.age,
this.date,
this.status,
});
String id;
String name;
String img;
Gender gender;
int age;
String date;
Status status;
factory ListElement.fromJson(Map<String, dynamic> json) => ListElement(
id: json["id"],
name: json["name"],
img: json["img"],
gender: genderValues.map[json["gender"]],
age: json["age"],
date: json["date"],
status: statusValues.map[json["status"]],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
"img": img,
"gender": genderValues.reverse[gender],
"age": age,
"date": date,
"status": statusValues.reverse[status],
};
}
enum Gender { M, F }
final genderValues = EnumValues({
"f": Gender.F,
"m": Gender.M
});
enum Status { ONBOARDED, ACTIVE, LEFT }
final statusValues = EnumValues({
"active": Status.ACTIVE,
"left": Status.LEFT,
"onboarded": Status.ONBOARDED
});
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;
}
}
Below is the db provider I have created to store the data.I need to still write the SQL command to properly get the data in the required sorting order.For the time being it is Select *
import 'dart:io';
import 'podo_file.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
//9-22 creating a Database object and instantiating it if not initialized.
class DBProvider {
static Database _database;
static final DBProvider db = DBProvider._();
DBProvider._();
Future<Database> get database async {
// If database exists, return database
if (_database != null) return _database;
// If database don't exists, create one
_database = await initDB();
return _database;
}
initDB() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
final path = join(documentsDirectory.path, 'Customer_Info.db');
return await openDatabase(path, version: 1, onOpen: (db) {},
onCreate: (Database db, int version) async {
await db.execute('CREATE TABLE CUSTOMER_DATA('
'id TEXT PRIMARY KEY,'
'name TEXT,'
'img TEXT,'
'gender TEXT'
'age INTEGER,'
'date TEXT,'
'status TEXT,'
')');
});
}
// Insert employee on database
createCustomer(ListElement newCustomer) async {
await deleteAllCustomers();
final db = await database;
final res = await db.insert('CUSTOMER_DATA', newCustomer.toJson());
return res;
}
// Delete all employees
Future<int> deleteAllCustomers() async {
final db = await database;
final res = await db.rawDelete('DELETE FROM CUSTOMER_DATA');
return res;
}
Future<List<ListElement>> getAllCustomers() async {
final db = await database;
final res = await db.rawQuery("SELECT * FROM CUSTOMER_DATA");
List<ListElement> list =
res.isNotEmpty ? res.map((c) => CustomerInfo.fromJson(c)).toList() : [];
return list;
}
}
Below is the service file I have created which will get the data:
import 'dart:convert';
import 'package:flutter/animation.dart';
import 'package:flutterappincablet/podo_file.dart';
import 'package:http/http.dart' as http;
import 'db_provider.dart';
class Services {
Future<List<ListElement>> getAllCustomers() async {
var url = "https://5w05g4ddb1.execute-api.ap-south-1.amazonaws.com/dev/profile/listAll";
final response = await http.get(url);
Map<String, dynamic> map = json.decode(response.body);
print('nnnnnnnnnn');
print(map);
List<dynamic> data = map["list"];
print('xxxxxxxxxxxxxxxxx');
print(data);
return (data as List).map((c) {
print('Inserting $c');
DBProvider.db.createCustomer(ListElement.fromJson(c));
}).toList();
}
}
Below is the screenshot of the error:
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()),
),
);
});
}));
}
}
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,
),
);
}
}