How to display json Nested Array in DropDown in Flutter? - flutter

I need to display the rows data in the dropdown. Any help is appreciated.
class _MyAppState extends State<MyAppdrop> {
List<LeadService> payloadListdropdown;
bool loading = false;
String _mySelection;
List<LeadService> payloadFromJson(String str) =>
List<LeadService>.from(
json.decode(str).map((x) => LeadService.fromJson(x)));
String payloadToJson(List<LeadService> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
Future<List<LeadService>> requestMethodspinner() async {
var url = "";
Map<String, String> headers = {
'Content-type': 'application/json',
'Accept': 'application/json',
};
final response = await http.post(url, headers: headers);
final responseJson = json.decode(response.body);
print(responseJson);
print(response.statusCode);
setState(() {
loading = true;
payloadListdropdown = payloadFromJson(response.body);
loading = false;
});
if (response.statusCode == 200) {}
else {
throw Exception('Failed to load internet');
}
return payloadListdropdown;
}
#override
void initState() {
super.initState();
this.requestMethodspinner();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("DropDown"),
),
body: new Center(
child: new DropdownButton(
items: payloadListdropdown.map((item) {
return new DropdownMenuItem(
child: new Text("${payloadListdropdown[0].rows[1].sName}"),
value: item[1].toString(),
);
}).toList(),
onChanged: (newVal) {
setState(() {
_mySelection = newVal;
});
},
value: _mySelection,
),
),
);
}
}
class LeadService {
int status;
String msg;
List<Rows> rows;
String sql;
dynamic reserved;
LeadService({
this.status,
this.msg,
this.rows,
this.sql,
this.reserved,
});
factory LeadService.fromJson(Map<String, dynamic> json) => LeadService(
status: json["status"],
msg: json["msg"],
rows: List<Rows>.from(json["rows"].map((x) => Rows.fromJson(x))),
sql: json["sql"],
reserved: json["reserved"],
);
Map<String, dynamic> toJson() => {
"status": status,
"msg": msg,
"rows": List<dynamic>.from(rows.map((x) => x.toJson())),
"sql": sql,
"reserved": reserved,
};
}
class Rows {
String ServicesId;
String sName;
String sCode;
Rows({
this.ServicesId,
this.sName,
this.sCode,
});
factory Rows.fromJson(Map<String, dynamic> json) => Rows(
//dropdownservicelist
ServicesId:json["ServicesId"],
sName:json["sName"],
sCode:json["sCode"],
);
Map<String, dynamic> toJson() => {
//dropdownservicelist
"ServicesId" :ServicesId,
"sName" : sName,
"sCode" : sCode,
};
}
Json data:
[
{
"status": 200,
"msg": "Ok",
"refcode": -1,
"trows": 13,
"rows": [
{
"ServicesId": "3",
"sName": "CFS",
"sCode": "CF"
},
{
"ServicesId": "2",
"sName": "Container aGENT",
"sCode": "CA"
},
{
"ServicesId": "1",
"sName": "Custom",
"sCode": "CB"
}
],
"sql": "Services",
"reserved": null
}
]

class _MyAppState extends State<MyAppdrop> {
Map payloadListdropdown;
Map _mySelection;
bool _loading = true;
requestMethodspinner() async {
var url = "";
Map<String, String> headers = {
'Content-type': 'application/json',
'Accept': 'application/json',
};
final response = await http.post(url, headers: headers);
final responseJson = json.decode(response.body);
print(responseJson);
print(response.statusCode);
if (response.statusCode == 200) {
setState(() {
loading = false;
payloadListdropdown = json.decode(response.body)[0];
_mySelection = payloadListdropdown['rows'][0];
});
}
else {
setState((){
loading = false;
});
throw Exception('Failed to load internet');
}
}
#override
void initState() {
super.initState();
requestMethodspinner();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("DropDown"),
),
body: new Center(
child: _loading && payloadListdropdown == null ?
ListTile(
title: Text('Loading...'),
leading:CircularProgressIndicator(),
)
:
payloadListdropdown == null ?
ListTile(
title: Text('Internet not available or Nothing found !'),
)
: DropdownButton(
items: payloadListdropdown['rows'].map<DropDownMenuItem<Map>>((item) {
return new DropdownMenuItem(
child: new Text(item['sName']),
//Other fields like sCode etc..
value: item,
);
}).toList(),
onChanged: (newVal) {
setState(() {
_mySelection = newVal;
print(_mySelection.toString())
});
},
value: _mySelection,
),
),
);
}
}

Related

Flutter dropdown with future builder

This is my data model
class RoleModel {
int? id;
String? role;
RoleModel({this.id, this.role});
RoleModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
role = json['role'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['role'] = role;
return data;
}
}
This is my code to get api data
List<RoleModel> roles = [];
Future<List<RoleModel>> getRoles() async {
try {
final response = await http
.get(Uri.parse('https://localhost:8000/roles'));
var data = jsonDecode(response.body.toString());
if (response.statusCode == 200) {
for (Map<String, dynamic> i in data) {
roles.add(RoleModel.fromJson(i));
}
return roles;
} else {
throw Exception('Failed to load roles:$response');
}
} catch (e) {
throw Exception('Failed due to: $e');
}
}
How can I create a dropdown button which will have 'id' as value and 'role' will be displayed as text?
You can use the below the line of sample code for dropdown widget
DropdownButton<String>(
items: <String>['One', 'Two', 'Three', 'Four'].map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (v) {},
),
you can create it like this
DropdownButton<int>(
items: [
DropdownMenuItem(
child: Text("${roleModel.role}"),
value: roleModel.id,
),
],
onChanged: (value) {},
),
You can also create a dropdown button just using a custom package from pub.dev :
Add the latest version of dropdown_button2 to your pubspec.yaml file from
[1]: https://pub.dev/packages/dropdown_button2/install
Run 'flutter pub add dropdown_button2' this command from your terminal.
Add 'import 'package:dropdown_button2/dropdown_button2.dart'; this line to your code page.
import 'dart:convert';
import 'package:dropdown_button2/custom_dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp(MyFlutterApp());
class MyFlutterApp extends StatelessWidget {
const MyFlutterApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
#override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
#override
List<String> get getAllRoles {
List<String> allRoles = [];
for (int i = 0; i < roles.length; i++) {
allRoles.add('${roles[i].id} ${roles[i].role}');
}
return allRoles; // String format of json taken from the web.
}
int index = 0;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Dropdown with id and role'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: CustomDropdownButton2(
hint: 'Select Item',
dropdownItems: getAllRoles,
value: getAllRoles[index],
buttonWidth: double.infinity,
dropdownWidth: double.infinity,
buttonElevation: 7,
onChanged: (value) {
setState(() {
index = getAllRoles.indexOf(value.toString());
});
},
),
),
);
}
}
class RoleModel {
int? id;
String? role;
RoleModel({this.id, this.role});
RoleModel.fromJson(Map<String, dynamic> json) {
id = json['id'];
role = json['role'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['id'] = id;
data['role'] = role;
return data;
}
}
List<RoleModel> roles = [];
Future<List<RoleModel>> getRoles() async {
try {
final response = await http.get(Uri.parse('https://localhost:8000/roles'));
var data = jsonDecode(response.body.toString());
if (response.statusCode == 200) {
for (Map<String, dynamic> i in data) {
roles.add(RoleModel.fromJson(i));
}
return roles;
} else {
throw Exception('Failed to load roles:$response');
}
} catch (e) {
throw Exception('Failed due to: $e');
}
}
I've received an error, because the http URL isn't accessible now. If you try it with a new URL, i think this code will work correctly.

Server response only showing circular progress dialog and not API data Flutter

I seriously need assistance. I want to show API data on a listview, but It is not showing, only showing circular progress dialog. My api function is working well as it is printing valid json data on console. When I show and navigate to ResultsPage, It just shows circular progress dialog and not the data. Can you tell me where am I going wrong, why the data is not displaying
Your help will be appreciated.
My API function
Future<List<Autogenerated>?> signInData() async {
final prefs = await SharedPreferences.getInstance();
final String? token = prefs.getString('token');
try {
Response response = await _dio.post('$_baseUrl/api/gateway',
data: {
"ClientPackageId": "0cdd231a-d7ad-4a68-a934-d373affb5100",
"PlatformId": "ios",
"ClientUserId": "AhmedOmar",
"VinNumber": VINumber
},
options: Options(
headers: {
"Content-Type": "application/json;charset=UTF-8",
"Charset": 'utf-8',
"Authorization": "Bearer $token",
},
));
print("data is here");
print(json.encode(response.data));
print(response.statusCode);
if (response.statusCode == 200) {
print("decoded");
List<Map<String, dynamic>> map = [];
map = List<Map<String, dynamic>>.from(
jsonDecode(json.encode(response.data)));
print(map);
// return List<Autogenerated>.from(
// response.data.map((i) => Autogenerated.fromJson(i)));
// return Autogenerated.fromJson(jsonDecode(json.encode(response.data)));
} else if (response.statusCode == 500) {
// call your refresh token api here and save it in shared preference
print(response.statusCode);
await getToken();
signInData();
} else {
throw Exception('Failed to load data');
}
} catch (e) {
print(e);
}
// return null;
}
Where I want to show the list
class ResultsPage extends StatefulWidget {
const ResultsPage({Key? key}) : super(key: key);
#override
_ResultsPageState createState() => _ResultsPageState();
}
class _ResultsPageState extends State<ResultsPage> {
Future<List<Autogenerated>?>? objectList;
_APIState? api;
#override
void initState() {
super.initState();
objectList = api?.signInData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
//centerTitle: true,
),
body: Center(
child: FutureBuilder<List<Autogenerated>?>(
future: objectList,
builder: (context, snapshot) {
if (snapshot.hasData) {
print("snapshot data:");
print(snapshot.hasData);
return Padding(
padding: const EdgeInsets.all(8.0),
child: ListView.builder(
itemCount: snapshot.data?.length,
itemBuilder: (context, index) {
var title = snapshot.data?[index].category;
// var company = snapshot.data[index]['company_name'];
// var skills = snapshot.data[index]['skills'];
// var description = snapshot.data[index]['description'];
// var positions = snapshot.data[index]['positions'];
return Card(
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.green.shade300,
),
borderRadius: BorderRadius.circular(15.0),
),
child: ListTile(
leading: Text(title!),
title: Text(title),
subtitle: Text(
title + '\n' + title,
),
trailing: Text(title),
),
);
},
));
} else if (snapshot.hasError) {
return Text('${snapshot.error}');
}
// By default, show a loading spinner.
return const CircularProgressIndicator();
},
),
));
}
}
You need to open the comment and return.
Future<List<Autogenerated>?> signInData() async {
final prefs = await SharedPreferences.getInstance();
final String? token = prefs.getString('token');
try {
Response response = await _dio.post('$_baseUrl/api/gateway',
data: {
"ClientPackageId": "0cdd231a-d7ad-4a68-a934-d373affb5100",
"PlatformId": "ios",
"ClientUserId": "AhmedOmar",
"VinNumber": VINumber
},
options: Options(
headers: {
"Content-Type": "application/json;charset=UTF-8",
"Charset": 'utf-8',
"Authorization": "Bearer $token",
},
));
print("data is here");
print(json.encode(response.data));
print(response.statusCode);
if (response.statusCode == 200) {
print("decoded");
List<Map<String, dynamic>> map = [];
map = List<Map<String, dynamic>>.from(
jsonDecode(json.encode(response.data)));
print(map);
// return List<Autogenerated>.from(
// response.data.map((i) => Autogenerated.fromJson(i)));
// return Autogenerated.fromJson(jsonDecode(json.encode(response.data)));
} else if (response.statusCode == 500) {
// call your refresh token api here and save it in shared preference
print(response.statusCode);
await getToken();
signInData();
} else {
throw Exception('Failed to load data');
}
} catch (e) {
print(e);
}
// return null;
}```

How to print error message from Backend in Flutter

Error message from backend appears in flutter terminal. How can I print this on the app?
I/flutter (16113): {"status":"Fail","error":{"code":1138,"message":"Kullanıcı zaten mevcut"}}
Service
class RegisterService extends ChangeNotifier {
bool isBack = false;
Future<RegisterResModel> register(RegisterReqModel data) async {
final http.Response response = await http.post(
Uri.parse("http://192.168.0.16:2526/api/v1/auths/register"),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(data.toJson()));
if (response.statusCode == 200) {
isBack = true;
print(response.body);
return RegisterResModel.fromJson(json.decode(response.body));
} else {
isBack = false;
throw Exception(response.body);
}
}
}
Res Model
class RegisterResModel {
String? message;
String? status;
RegisterResModel({this.message, this.status});
RegisterResModel.fromJson(Map<String, dynamic> json) {
message = json['message'];
status = json['status'];
}
Map<String, dynamic> toJson(decode) {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['message'] = message;
data['status'] = status;
return data;
}
}
You need to add one class to store the error details.
class ErrorModel{
String? message;
int? code;
ErrorModel({this.message, this.code});
ErrorModel.fromJson(Map<String, dynamic> json) {
message = json['message'];
code = json['code'];
}
Map<String, dynamic> toJson(decode) {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['message'] = message;
data['code'] = code;
return data;
}
}
You can add this model to your own Register class.
class RegisterResModel {
String? message;
String? status;
ErrorModel? error;
RegisterResModel({this.message, this.status, this.error});
fromJson(Map<String, dynamic> json) {
message = json['message'];
status = json['status'];
error = ErrorModel.fromJson(json['error']);
}
Map<String, dynamic> toJson(decode) {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['message'] = message;
data['status'] = status;
return data;
}
}
similar to you have parse the response, you can now get the error information as well. Please check sample code as below.
class RegisterService extends ChangeNotifier {
bool isBack = false;
Future<RegisterResModel> register(RegisterReqModel data) async {
final http.Response response = await http.post(
Uri.parse("http://192.168.0.16:2526/api/v1/auths/register"),
headers: <String, String>{
'Content-Type': 'application/json; charset=UTF-8',
},
body: jsonEncode(data.toJson()));
if (response.statusCode == 200) {
isBack = true;
print(response.body);
return RegisterResModel.fromJson(json.decode(response.body));
} else {
isBack = false;
return RegisterResModel.fromJson(json.decode(response.body));
}
}
}
Now you can return register class and check for status fail or pass based on the response and show the error.
To show the error, there are multiple options like Show Alert dialog, Show snackbar. Those are listed as below
Alert dialog:
showAlertDialog(BuildContext context) {
// set up the button
Widget okButton = TextButton(
child: Text("OK"),
onPressed: () { },
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: Text("My title"),
content: Text("This is my message."),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
Snackbar :
import 'package:flutter/material.dart';
void main() => runApp(const SnackBarDemo());
class SnackBarDemo extends StatelessWidget {
const SnackBarDemo({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'SnackBar Demo',
home: Scaffold(
appBar: AppBar(
title: const Text('SnackBar Demo'),
),
body: const SnackBarPage(),
),
);
}
}
class SnackBarPage extends StatelessWidget {
const SnackBarPage({super.key});
#override
Widget build(BuildContext context) {
return Center(
child: ElevatedButton(
onPressed: () {
final snackBar = SnackBar(
content: const Text('Yay! A SnackBar!'),
action: SnackBarAction(
label: 'Undo',
onPressed: () {
// Some code to undo the change.
},
),
);
// Find the ScaffoldMessenger in the widget tree
// and use it to show a SnackBar.
ScaffoldMessenger.of(context).showSnackBar(snackBar);
},
child: const Text('Show SnackBar'),
),
);
}
}
You can wrap your main code in try catch block and incase it shows an exception/error, you can show a toast or snackBar to show the message.
Learn more about-
Try-catch block
toast messages
snackbar messages
You could use an Alert Dialog to ensure that the error is seen and acknowledged for whatever reason you're doing this.

Flutter display server data / response from json

I have built a page which reads the json from recipeURL and I wish for it to display the product_name value in the json file. However for some reason my future fetchData () class isn't being read as none of the text in my if else statement is being displayed. Am I missing a simple oversight here?
EDIT: The main dart file is my main screen. This is where my navbar is created. Users are redirected to other pages when they click on the corresponding icon. Im having trouble passing BarcodePage(title:title); as parameters in my main file,26th line, can be found under Class MyAppState extends State<MyApp> {
My main dart file:
import 'package:flutter/material.dart';
import 'pages/BarcodePage.dart';
import 'pages/FoodPage.dart';
import 'pages/RecipePage.dart';
import 'pages/ShoppingPage.dart';
void main() {
runApp(MaterialApp(debugShowCheckedModeBanner: false, home: MyApp()),);
}
class MyApp extends StatefulWidget {
#override
State<StatefulWidget> createState(){
return MyAppState();
}
}
class MyAppState extends State<MyApp> {
int _selectedPage =0;
final _pageOptions= [
FoodPage(),
RecipePage(),
BarcodePage(title: ,),
ShoppingPage(),
];
#override
Widget build(BuildContext context) {
return MaterialApp(
//title: 'Best B4',
theme: ThemeData(
primarySwatch: Colors.teal,),
debugShowCheckedModeBanner: false,
home: Scaffold (
appBar: AppBar(
title:Text(
'BestB4',
style: TextStyle(
fontFamily: 'PacificoRegular',
fontSize: 30,
),
),
backgroundColor: Colors.teal,
elevation: 20,
actions: [
IconButton(
icon: Icon(Icons.qr_code_2_rounded),
tooltip: 'Add item',
onPressed:(){
Navigator.push(
context,
MaterialPageRoute(builder: (context) => BarcodePage()));
},
)
],
//ONPRESSED MENU OPEN
),
body:_pageOptions[_selectedPage],
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
backgroundColor: Colors.teal,
selectedItemColor: Colors.white,
unselectedItemColor: Colors.white70,
iconSize: 40,
selectedFontSize: 15,
unselectedFontSize: 15,
currentIndex:_selectedPage,
onTap: (int index) {
setState(() {
_selectedPage = index;
});
},
items: [
BottomNavigationBarItem(
icon:Icon(Icons.restaurant_rounded),
label: 'Food',
), //, title:Text('Food')
BottomNavigationBarItem(
icon:Icon(Icons.menu_book_rounded),
label:'Recipes',
),//, title:Text('Recipes')
BottomNavigationBarItem(
icon:Icon(Icons.add_outlined),
label:'Add',
),//, title:Text('Add')
BottomNavigationBarItem(
icon:Icon(Icons.shopping_cart_rounded),
label:'Shopping',
),//,title:Text('Shopping')
],
),
),
);
}
}
My BarcodePage dart file:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as p;
import 'package:flutter/services.dart';
import 'package:barcode_scan2/barcode_scan2.dart';
import 'package:http/http.dart';
class BarcodePage extends StatefulWidget{
const BarcodePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_BarcodePageState createState() => _BarcodePageState();
}
var futuredata = {};
class _BarcodePageState extends State<BarcodePage> {
int counter=0;
String result= "";
Future _scanBarcode() async{
try{
ScanResult scanResult = await BarcodeScanner.scan();
String barcodeResult = scanResult.rawContent;
setState(() {
result = barcodeResult;
});
} on PlatformException catch (ex) {
if (ex.code == BarcodeScanner.cameraAccessDenied) {
setState((){
result = "CAMERA PERMISSION WAS DENIED. \n EDIT THIS IN YOUR SETTINGS";
});
}else {
setState(() {
result = "404 ERROR UNKNOWN $ex";
});
}
} on FormatException {
setState(() {
result = "SCAN AN ITEM";
});
} catch (ex){
setState(() {
result = "404 ERROR UNKNOWN $ex";
});
}
}
#override
void initState() {}
fetchmydata() async {
var request = p.Request(
'GET',
Uri.parse(
'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));
StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// print(await response.stream.bytesToString());
var data = await response.stream.bytesToString();
futuredata = json.decode(data);
} else {
print(response.reasonPhrase);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.teal,
title:Text('Add an item',
style: TextStyle(
fontFamily: 'Fredoka',
fontSize: 25,
),
),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
FutureBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return Center(
child: Container(
child: CircularProgressIndicator(),
height: 50,
width: 50,
),
);
else if (snapshot.connectionState == ConnectionState.done)
return ListTile(
title: Text(futuredata["product"]["product_name"].toString()),
subtitle: Text("France:" +
futuredata["product"]["product_name_en"].toString()),
);
else {
return Container(
child: CircularProgressIndicator(),
height: 50,
width: 50,
);
}
},
future: fetchmydata(),
)
],
),
floatingActionButton: FloatingActionButton.extended(
backgroundColor: Color.fromRGBO(51, 171, 160, 100),
icon: Icon(Icons.camera_alt),
label: Text("Scan"),
onPressed: _scanBarcode,
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
);
}
}
The Json file looks like this:
JSON LINK: https://world.openfoodfacts.org/api/v0/product/5060391623139.json
You can read your json like this
var futuredata = {};
var productname= futuredata["product"]["product_name"]
Your fetch method like this
fetchmydata() async {
var request = p.Request(
'GET',
Uri.parse(
'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));
StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// print(await response.stream.bytesToString());
var data = await response.stream.bytesToString();
futuredata = json.decode(data);
} else {
print(response.reasonPhrase);
}
}
With model Class
SampleModel? Mymodel = null;
fetchmydata() async {
var request = p.Request(
'GET',
Uri.parse(
'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));
StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// print(await response.stream.bytesToString());
var data = await response.stream.bytesToString();
futuredata = json.decode(data);
Mymodel = SampleModel.fromJson(futuredata);
} else {
print(response.reasonPhrase);
}
}
in the method we first read data from json as string or text
then we decode the string type or text from server to map type
SampleCode Dartpad live code check
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
import 'package:http/http.dart' as p;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
var futuredata = {};
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
#override
void initState() {}
fetchmydata() async {
var request = p.Request(
'GET',
Uri.parse(
'https://world.openfoodfacts.org/api/v0/product/5060391623139.json'));
StreamedResponse response = await request.send();
if (response.statusCode == 200) {
// print(await response.stream.bytesToString());
var data = await response.stream.bytesToString();
futuredata = json.decode(data);
} else {
print(response.reasonPhrase);
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
FutureBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting)
return Center(
child: Container(
child: CircularProgressIndicator(),
height: 50,
width: 50,
),
);
else if (snapshot.connectionState == ConnectionState.done)
return ListTile(
title: Text(futuredata["product"]["product_name"].toString()),
subtitle: Text("France:" +
futuredata["product"]["product_name_en"].toString()),
);
else {
return Container(
child: CircularProgressIndicator(),
height: 50,
width: 50,
);
}
},
future: fetchmydata(),
)
],
),
);
}
}
Sample ModelClass
///
/// Code generated by jsonToDartModel https://ashamp.github.io/jsonToDartModel/
///
class SampleModelProduct {
/*
{
"_id": "5060391623139",
"_keywords": [
"peanut"
],
"product_name": "Peanut butter",
"product_name_en": "Peanut butter",
"product_name_fr": "Peanut butter"
}
*/
String? Id;
List<String?>? Keywords;
String? productName;
String? productNameEn;
String? productNameFr;
SampleModelProduct({
this.Id,
this.Keywords,
this.productName,
this.productNameEn,
this.productNameFr,
});
SampleModelProduct.fromJson(Map<String, dynamic> json) {
Id = json['_id']?.toString();
if (json['_keywords'] != null) {
final v = json['_keywords'];
final arr0 = <String>[];
v.forEach((v) {
arr0.add(v.toString());
});
Keywords = arr0;
}
productName = json['product_name']?.toString();
productNameEn = json['product_name_en']?.toString();
productNameFr = json['product_name_fr']?.toString();
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['_id'] = Id;
if (Keywords != null) {
final v = Keywords;
final arr0 = [];
v!.forEach((v) {
arr0.add(v);
});
data['_keywords'] = arr0;
}
data['product_name'] = productName;
data['product_name_en'] = productNameEn;
data['product_name_fr'] = productNameFr;
return data;
}
}
class SampleModel {
/*
{
"code": "5060391623139",
"product": {
"_id": "5060391623139",
"_keywords": [
"peanut"
],
"product_name": "Peanut butter",
"product_name_en": "Peanut butter",
"product_name_fr": "Peanut butter"
},
"status": 1,
"status_verbose": "product found"
}
*/
String? code;
SampleModelProduct? product;
int? status;
String? statusVerbose;
SampleModel({
this.code,
this.product,
this.status,
this.statusVerbose,
});
SampleModel.fromJson(Map<String, dynamic> json) {
code = json['code']?.toString();
product = (json['product'] != null)
? SampleModelProduct.fromJson(json['product'])
: null;
status = json['status']?.toInt();
statusVerbose = json['status_verbose']?.toString();
}
Map<String, dynamic> toJson() {
final data = <String, dynamic>{};
data['code'] = code;
if (product != null) {
data['product'] = product!.toJson();
}
data['status'] = status;
data['status_verbose'] = statusVerbose;
return data;
}
}
try creating a .g.dart file using flutter packages pub run build_runner build. flutter automatically will create your binding class factory. once you have the binding classes created flutter will automatically code your binding class, including nested classes. I personally think automation is the way to handle all interactions with json from the server. The reason you want to use the future .g.dart code generator is to reduce the possibility of error and incorrect type casting.
file.dart
factory ProductView.fromJson(Map<String, dynamic> json) =>
_$ProductFromJson(json);
Map<String, dynamic> toJson() => _$ProductViewToJson(this);
file.g.dart
ProductView _$ProductViewFromJson(Map<String, dynamic> json) {
return
ProductView(
json['field1'] as int,
json['field2'] as String,
json['field3'] == null
? null
: DateTime.parse(json['field3'] as String),
);
}
Map<String, dynamic> _$ProjectViewToJson(ProductView instance) =>
<String, dynamic>{
'field1': instance.field1,
'field2': instance.field2,
'field3': instance.field3?.toIso8601String(),
};
decoding the json
var client = http.Client();
Map<String, String> headers = new HashMap();
headers['Accept'] = 'application/json';
headers['Content-Type'] = 'application/json';
headers['Authorization'] = 'Bearer $token';
var response = await client.get(url, headers: headers).timeout(_TIMEOUT);
var parsed = json.decode(response.body);
var view = ProductView.fromJson(parsed);

_TypeError (type '(dynamic) => Article' is not a subtype of type '(String, dynamic) => MapEntry<dynamic, dynamic>' of 'transform')

The error usually occures when I scroll to the end of a list of post.
Here is the code for fetching posts from the Word press api
Future<List<dynamic>> fetchLatestArticles(int page) async {
try {
var response = await http.get(
'$WORDPRESS_URL/wp-json/wp/v2/posts/?page=$page&per_page=10&_fields=id,date,title,content,custom,link');
if (this.mounted) {
if (response.statusCode == 200) {
setState(() {
latestArticles.addAll(json
.decode(response.body)
.map((m) => Article.fromJson(m))
.toList());
if (latestArticles.length % 10 != 0) {
_infiniteStop = true;
} else {
_infiniteStop = false;
}
});
return latestArticles;
}
setState(() {
_infiniteStop = true;
});
}
} on SocketException {
throw 'No Internet connection';
}
return latestArticles;
}
here is a sample of response from the api call
[
{
"id": "",
"date": "",
"link": " ",
"title": {
"rendered": " "
},
"content": {
"rendered": " ",
"protected": false
}
},
{
"id": "",
"date": " ",
"link": " ",
"title": {
"rendered": " "
},
"content": {
"rendered": " ",
"protected": false
}
}
]
You can copy paste run full code below
You can use latestArticles.addAll(articleFromJson(response.body));
code snippet
List<Article> articleFromJson(String str) => List<Article>.from(json.decode(str).map((x) => Article.fromJson(x)));
...
if (this.mounted) {
if (response.statusCode == 200) {
setState(() {
latestArticles.addAll(articleFromJson(response.body));
working demo
full code
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
List<Article> articleFromJson(String str) =>
List<Article>.from(json.decode(str).map((x) => Article.fromJson(x)));
String articleToJson(List<Article> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Article {
Article({
this.id,
this.date,
this.link,
this.title,
this.content,
});
String id;
String date;
String link;
Title title;
Content content;
factory Article.fromJson(Map<String, dynamic> json) => Article(
id: json["id"],
date: json["date"],
link: json["link"],
title: Title.fromJson(json["title"]),
content: Content.fromJson(json["content"]),
);
Map<String, dynamic> toJson() => {
"id": id,
"date": date,
"link": link,
"title": title.toJson(),
"content": content.toJson(),
};
}
class Content {
Content({
this.rendered,
this.protected,
});
String rendered;
bool protected;
factory Content.fromJson(Map<String, dynamic> json) => Content(
rendered: json["rendered"],
protected: json["protected"],
);
Map<String, dynamic> toJson() => {
"rendered": rendered,
"protected": protected,
};
}
class Title {
Title({
this.rendered,
});
String rendered;
factory Title.fromJson(Map<String, dynamic> json) => Title(
rendered: json["rendered"],
);
Map<String, dynamic> toJson() => {
"rendered": rendered,
};
}
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 _counter = 0;
List<Article> latestArticles = [];
bool _infiniteStop;
Function _future;
Future<List<Article>> fetchLatestArticles(int page) async {
try {
/*var response = await http.get(
'$WORDPRESS_URL/wp-json/wp/v2/posts/?page=$page&per_page=10&_fields=id,date,title,content,custom,link');*/
String jsonString = '''
[
{
"id": "123",
"date": "",
"link": " ",
"title": {
"rendered": "abc"
},
"content": {
"rendered": " ",
"protected": false
}
},
{
"id": "456",
"date": " ",
"link": " ",
"title": {
"rendered": "def"
},
"content": {
"rendered": " ",
"protected": false
}
}
]
''';
http.Response response = http.Response(jsonString, 200);
if (this.mounted) {
if (response.statusCode == 200) {
setState(() {
latestArticles.addAll(articleFromJson(response.body));
if (latestArticles.length % 10 != 0) {
_infiniteStop = true;
} else {
_infiniteStop = false;
}
});
return latestArticles;
}
setState(() {
_infiniteStop = true;
});
}
} on SocketException {
throw 'No Internet connection';
}
return latestArticles;
}
#override
void initState() {
_future = fetchLatestArticles;
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: FutureBuilder(
future: _future(1),
builder: (context, AsyncSnapshot<List<Article>> snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('none');
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.active:
return Text('');
case ConnectionState.done:
if (snapshot.hasError) {
return Text(
'${snapshot.error}',
style: TextStyle(color: Colors.red),
);
} else {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (context, index) {
return Card(
elevation: 6.0,
child: Padding(
padding: const EdgeInsets.only(
top: 6.0,
bottom: 6.0,
left: 8.0,
right: 8.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(snapshot.data[index].title.rendered),
Spacer(),
Text(
snapshot.data[index].id,
),
],
),
));
});
}
}
}));
}
}