Related
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:
So, I am pretty new to async programming in flutter, I came across a json fine which looks like this:
[{
"Bus": ["a", "b", "c"],
"Stops": ["1", "2", "3", "4"]
}]
So, I made a class:
class StopInfo {
final List Bus;
final List Stop;
StopInfo({this.Bus, this.Stop});
factory StopInfo.fromJson(Map<String, dynamic> json) {
return StopInfo(
busNames: json["Bus"],
busStops: json["Stops"]
);
}
}
Now, if I am fetching Data like this:
Future<StopInfo> fetchStopData() async {
var response = await http.get(url);
print(response.body);
StopInfo _stopInfo = StopInfo();
if (response.statusCode == 200) {
/*
What do I do here
*/
} else {
throw Exception('Failed to get data');
}
}
I am confused what to do here, Should I change something else?
Thanks in advance.
here is a simple example which shows how you can extract and use JSON data:
import "package:flutter/material.dart";
import "dart:convert";
import "package:http/http.dart" as http;
class JsonMultyParse extends StatefulWidget {
#override
_JsonMultyParseState createState() => _JsonMultyParseState();
}
class _JsonMultyParseState extends State<JsonMultyParse> {
final String apiURL = 'https://jsonplaceholder.typicode.com/users';
List<dynamic> users = [];
void fetchJSONData() async {
var jsonResponse = await http.get(apiURL);
if (jsonResponse.statusCode == 200) {
final jsonItems =
json.decode(jsonResponse.body).cast<Map<String, dynamic>>();
print(jsonItems[0]["address"]["street"]);
setState(() {
users = jsonItems;
});
for (dynamic user in users) {
print(user["address"]["street"]);
}
} else {
throw Exception('Failed to load data from internet');
}
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Container(
child: Column(
children: <Widget>[
SizedBox(height: 20),
RaisedButton(
onPressed: fetchJSONData,
child: Text("Fetch Data"),
),
Expanded(
child: ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return Card(
child: Container(
height: 50,
padding: const EdgeInsets.all(8.0),
child: Text(
users[index]["address"]["street"],
),
),
);
}),
)
],
),
),
));
}
}
Output:
import 'dart:convert';
Future<List<StopInfo>> fetchStopData() async {
var response = await http.get(url);
print(response.body);
StopInfo _stopInfo = StopInfo();
if (response.statusCode == 200) {
var body = jsonDecode(response.body);
if(body is List) //check if it's a List, as per your example I suppose it will always be a list
return List<StopInfo>.from(body.map(map) => StopInfo.fromJson(map));
else if(body is Map) //check if it's a Map
return [StopInfo.fromJson(body)];
} else {
throw Exception('Failed to get data');
}
}
jsonDecode is part of dart:convert and decode a String to a dynamic value (can be a List or a Map) according to the form of the JSON data it decodes, after that you just convert it to List of StopInfo (if thats what you were expecting from the JSON
Add the following Function in your StopInfo class, which will convert jsonbody into List.
List<StopInfo> stopInfoResponseFromJson(String str) {
final jsonData = json.decode(str);
return new List<StopInfo>.from(jsonData.map((x) => StopInfo.fromJson(x)));
}
Use the above function in your fetchStopData function, like following.
String response = jsonEncode(StopInfo.body);
List<StopInfo> stopInfoResponse = stopInfoResponseFromJson(response);
Try this,
Future<StopInfo> fetchStopData() async {
var response = await http.get(url);
print(response.body);
StopInfo _stopInfo = StopInfo();
if (response.statusCode == 200) {
return StopInfo.fromJson(json.decode(response.body.toString())[0]);
} else {
throw Exception('Failed to get data');
}
}
also modify the StopInfo
factory StopInfo.fromJson(Map<String, dynamic> json) {
List<String> buses=List();
List<String> stops=List();
json["Bus"].forEach((bus)=>buses.add(bus));
json["Stops"].forEach((stop)=>stops.add(stop));
return StopInfo(
busNames: buses,
busStops: stops
);
}
Can you try the following. I generated the class using https://app.quicktype.io/
Change your StopInfo class as
// To parse this JSON data, do
//
// final stopInfo = stopInfoFromJson(jsonString);
import 'dart:convert';
class StopInfo {
StopInfo({
this.bus,
this.stops,
});
List<String> bus;
List<String> stops;
factory StopInfo.fromJson(Map<String, dynamic> json) => StopInfo(
bus: List<String>.from(json["Bus"].map((x) => x)),
stops: List<String>.from(json["Stops"].map((x) => x)),
);
Map<String, dynamic> toJson() => {
"Bus": List<dynamic>.from(bus.map((x) => x)),
"Stops": List<dynamic>.from(stops.map((x) => x)),
};
}
and to convert back and forth use these functions
List<StopInfo> stopInfoFromJson(String str) => List<StopInfo>.from(json.decode(str).map((x) => StopInfo.fromJson(x)));
String stopInfoToJson(List<StopInfo> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
You probably need to use the first one and use the list to create the display widgets. The following is a minimal example
class _MyHomePageState extends State<MyHomePage> {
String busStops = '''
[{
"Bus": ["a", "b", "c"],
"Stops": ["1", "2", "3", "4"]
}]
''';
List<StopInfo> allStops = [];
List<Widget> cardsList = [];
#override
void initState() {
super.initState();
loadPrelimData();
}
void loadPrelimData(){
setState(() {
allStops.clear();
allStops = stopInfoFromJson(busStops);
fillColumnChildren();
});
}
void fillColumnChildren(){
cardsList.clear();
allStops.forEach((stopInfos) {
String stops = "";
stopInfos.stops.forEach((element) { stops += element + ", "; });
stopInfos.bus.forEach((element) {
cardsList.add(
//the widget that will be displayed
Card(
child: ListTile(title: Text("Bus:" + element),
subtitle: Text("Stops:" + stops),
),
)
);
});
});
}
List<StopInfo> stopInfoFromJson(String str) => List<StopInfo>.from(json.decode(str).map((x) => StopInfo.fromJson(x)));
String stopInfoToJson(List<StopInfo> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Bus stops"),),
body: Center(
child: Column(children: cardsList)
));
}
}
I get the following
You model
class StopInfo {
final List<String> busList;
final List<String> stopList;
StopInfo({
this.busList,
this.stopList,
});
StopInfo copyWith({
List<String> busList,
List<String> stopList,
}) {
return StopInfo(
busList: busList ?? this.busList,
stopList: stopList ?? this.stopList,
);
}
Map<String, dynamic> toMap() {
return {
'busList': busList,
'stopList': stopList,
};
}
static StopInfo fromMap(Map<String, dynamic> map) {
if (map == null) return null;
return StopInfo(
busList: List<String>.from(map['busList']),
stopList: List<String>.from(map['stopList']),
);
}
String toJson() => json.encode(toMap());
static StopInfo fromJson(String source) => fromMap(json.decode(source));
#override
String toString() => 'StopInfo(busList: $busList, stopList: $stopList)';
#override
bool operator ==(Object o) {
if (identical(this, o)) return true;
return o is StopInfo &&
listEquals(o.busList, busList) &&
listEquals(o.stopList, stopList);
}
#override
int get hashCode => busList.hashCode ^ stopList.hashCode;
}
Your Service
Future<StopInfo> fetchStopData() async {
var response = await http.get(url);
print(response.body);
if (response.statusCode == 200) {
return StopInfo.fromJson(response.body);
} else {
throw Exception('Failed to get data');
}
}
Getting below Format exception when I am trying to decode Json response. Please help out.
Unhandled Exception: FormatException: Unexpected character (at character 3)
[{table_no: 1}, {table_no: 2}, {table_no: 3}]
[
{
"table_no": "1"
},
{
"table_no": "2"
},
{
"table_no": "3"
}
]
Future<Response> pos_client_table() async {
String url =
'https://xxxxxx.com/api/v1/table?branch_id=1';
Response response;
Dio dio = new Dio();
dio.options.headers = {'Authorization': prefs.getString('posclient_token')};
try {
response = await dio.get(url);
var jso = json.decode(response.toString());
Fluttertoast.showToast(
msg: "$jso",
toastLength: Toast.LENGTH_SHORT,
gravity: ToastGravity.BOTTOM,
timeInSecForIos: 1,
backgroundColor: Colors.red,
textColor: Colors.white,
fontSize: 16.0);
} catch (e) {
print(e);
}
return response;
}
void CallTableUrl() async {
Response response = await pos_client_table();
List<Map> _myJson = json.decode(response.toString());
showInSnackBar('$_myJson');
}
Edit add dio parse example and parse picture
Response response;
Dio dio = new Dio();
response = await dio.get("http://yoursite");
print(response);
print(response.data.toString());
List<Payload> payload = payloadFromJson(response.data);
print({payload[0].tableNo});
Assume dio already return correct json string is
String jsonString = '[{"table_no": "1"},{"table_no": "2"},{"table_no": "3"}]';
Step 1: Parse jsonString with payload class
List<Payload> payload = payloadFromJson(jsonString);
payload class
List<Payload> payloadFromJson(String str) =>
List<Payload>.from(json.decode(str).map((x) => Payload.fromJson(x)));
String payloadToJson(List<Payload> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Payload {
String tableNo;
Payload({
this.tableNo,
});
factory Payload.fromJson(Map<String, dynamic> json) => Payload(
tableNo: json["table_no"],
);
Map<String, dynamic> toJson() => {
"table_no": tableNo,
};
}
Step 2: transfer this payload to required map of DropdownMenuItem
for (var i = 0; i < payload.length; i++) {
_myJson.add({'id': payload[i].tableNo, 'name': payload[i].tableNo});
}
Step 3: populate DropdownMenuItem
DropdownButton<String>(
isDense: true,
hint: Text("${payload[0].tableNo}"),
value: _mySelection,
onChanged: (String Value) {
setState(() {
_mySelection = Value;
});
print(_mySelection);
},
items: _myJson.map((Map map) {
return DropdownMenuItem<String>(
value: map["id"].toString(),
child: Text(
map["name"],
),
);
}).toList(),
),
full code
import 'package:flutter/material.dart';
import 'dart:convert';
List<Payload> payloadFromJson(String str) =>
List<Payload>.from(json.decode(str).map((x) => Payload.fromJson(x)));
String payloadToJson(List<Payload> data) =>
json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Payload {
String tableNo;
Payload({
this.tableNo,
});
factory Payload.fromJson(Map<String, dynamic> json) => Payload(
tableNo: json["table_no"],
);
Map<String, dynamic> toJson() => {
"table_no": tableNo,
};
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
// This widget is the home page of your application. It is stateful, meaning
// that it has a State object (defined below) that contains fields that affect
// how it looks.
// This class is the configuration for the state. It holds the values (in this
// case the title) provided by the parent (in this case the App widget) and
// used by the build method of the State. Fields in a Widget subclass are
// always marked "final".
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
String jsonString = '[{"table_no": "1"},{"table_no": "2"},{"table_no": "3"}]';
List<Payload> payload = payloadFromJson(jsonString);
List<Map> _myJson = [];
class _MyHomePageState extends State<MyHomePage> {
String _mySelection;
#override
void initState() {
for (var i = 0; i < payload.length; i++) {
_myJson.add({'id': payload[i].tableNo, 'name': payload[i].tableNo});
}
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
Container(
height: 500.0,
child: Center(
child: DropdownButton<String>(
isDense: true,
hint: Text("${payload[0].tableNo}"),
value: _mySelection,
onChanged: (String Value) {
setState(() {
_mySelection = Value;
});
print(_mySelection);
},
items: _myJson.map((Map map) {
return DropdownMenuItem<String>(
value: map["id"].toString(),
child: Text(
map["name"],
),
);
}).toList(),
),
),
),
],
),
),
);
}
}
I'm facing the same issue since i start coding yesterday on my project which has a part of getting some of json data from a given api.
My api link is: http://alkadhum-col.edu.iq/wp-json/wp/v2/posts?_embed
I'm working on flutter SDK and i'm confused why it is not working with me!, my job is to get only link, title, and source_url objects but i cannot get it.
I tried the following code in flutter documentation
https://flutter.dev/docs/cookbook/networking/fetch-data
and after some of modification according to my needs didn't got any data.
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
Future<Post> fetchPost() async {
final response =
await http.get('http://alkadhum-col.edu.iq/wp-json/wp/v2/posts/');
if (response.statusCode == 200) {
// If the call to the server was successful, parse the JSON
return Post.fromJson(json.decode(response.body));
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
class Post {
final int id;
String title;
String link;
Post({this.id, this.title, this.link});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
id: json['id'],
title: json['title'].toString(),
link: json['link'].toString()
);
}
}
void main() => runApp(MyApp(post: fetchPost()));
class MyApp extends StatelessWidget {
final Future<Post> post;
MyApp({Key key, this.post}) : super(key: key);
#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<Post>(
future: post,
builder: (context, snapshot) {
if (snapshot.hasData) {
return Text(snapshot.data.link);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner
return CircularProgressIndicator();
},
),
),
),
);
}
}
I only got the meesage below:
Type List dynamic is not a subtype of type Map String, dynamic
Any help will be appreciated.
Thanks in advance.
Your JSON response is of type List<dynamic> but you are taking response in Map String, dynamic but you can do something like this
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:clickmeetplay/iam/user/postbean.dart';
import 'package:http/http.dart' as http;
class PostHome extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(home: Scaffold(body: PostScreen(),),);
}
}
class PostScreen extends StatefulWidget {
#override
_PostScreenState createState() => _PostScreenState();
}
class _PostScreenState extends State<PostScreen> {
List<Post> _postList =new List<Post>();
Future<List<Post> > fetchPost() async {
final response =
await http.get('http://alkadhum-col.edu.iq/wp-json/wp/v2/posts/');
if (response.statusCode == 200) {
// If the call to the server was successful, parse the JSON
List<dynamic> values=new List<dynamic>();
values = json.decode(response.body);
if(values.length>0){
for(int i=0;i<values.length;i++){
if(values[i]!=null){
Map<String,dynamic> map=values[i];
_postList .add(Post.fromJson(map));
debugPrint('Id-------${map['id']}');
}
}
}
return _postList;
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
#override
Widget build(BuildContext context) {
return Container();
}
#override
void initState() {
fetchPost();
}
}
Bean class
class Post {
final int id;
String title;
String link;
Post({this.id, this.title, this.link});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
id: json['id'],
title: json['title'].toString(),
link: json['link'].toString()
);
}
}
You need to change your class. you need to create your class structure as per the JSON response.
class Post {
int id;
String title;
String link;
Post({this.id, this.title, this.link});
factory Post.fromJson(Map<String, dynamic> json) {
return Post(
id: json['id'],
title: title = json['title'] != null ? new Title.fromJson(json['title']) : null;
link: json['link'].toString()
);
}
}
class Title {
String rendered;
Title({this.rendered});
Title.fromJson(Map<String, dynamic> json) {
rendered = json['rendered'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['rendered'] = this.rendered;
return data;
}
}
Then, in your API method. As the response, you are getting is a JSON array. So, take that in a list and cast the response into your JSON class.
Future<List<Post>> fetchPost() async {
final response =
await http.get('http://alkadhum-col.edu.iq/wp-json/wp/v2/posts/');
if (response.statusCode == 200) {
// If the call to the server was successful, parse the JSON
var lst = response.body as List;
return lst.map((d) => Post.fromJson(d)).toList();
} else {
// If that call was not successful, throw an error.
throw Exception('Failed to load post');
}
}
You can always use tools like https://javiercbk.github.io/json_to_dart/ to create Dart classes from complex JSON. Which saves a lot of time.
Try below code:
factory Post.fromMap(Map<String, dynamic> json) {
return Post(
id: json['id'],
title: json['title'].cast<String>(),
link: json['link'].cast<String>()
);
}
**Create Api Class**
class ApiUtils {
static String baseUrl = "http://example/";
}
**Create Model**
class EventModel {
String title;
EventModel({this.title});
EventModel.fromJson(Map<String, dynamic> json) {
title = json['Title'] ?? "";
}
}
**Create Service**
import 'package:http/http.dart' as http;
import 'package:NoticeModel.dart';
import 'dart:convert';
class NoticeService {
bool error = false;
bool loading = true;
var notice;
bool noticeDetailserror = false;
bool noticeetailsloading = true;
Future<void> getNotice(dynamic input) async {
try {
noticeDetailserror = false;
http.Response response = await http.post(ApiUtils.noticeApi,
body: input, headers: {'Content-type': 'application/json'});
Map data = jsonDecode(response.body);
if (data["Status"] == true) {
notice = data["Data"];
notice = notice.map((_data) {
return new NoticeModel.fromJson(_data);
}).toList();
print(notice);
noticeetailsloading = false;
} else {
throw data;
}
} catch (e) {
print(e);
noticeetailsloading = false;
noticeDetailserror = true;
}
}
}
**Main Page**
var body =
json.encode({"IsActive": true, "IsDelete": false, "CompanyId": 18});
List<dynamic> data;
var count = 0;
bool loading = true;
bool error = false;
void getNoticeDetails() async {
setState(() {
error = false;
loading = true;
});
// SharedPreferences prefs = await SharedPreferences.getInstance();
NoticeService instance = NoticeService();
await instance.getNotice(body);
data = instance.notice;
if (instance.noticeDetailserror == false) {
setState(() {
count = data.length;
loading = false;
});
} else {
setState(() {
loading = false;
error = true;
});
Toast.show("Error Getting Data", context,
duration: Toast.LENGTH_SHORT, gravity: Toast.BOTTOM);
}
}
#override
void initState() {
super.initState();
getNoticeDetails();
}
body: loading == true
? LinearProgressIndicator()
: error == true
? RetryWidget(
onRetry: getNoticeDetails,
)
: SafeArea(
SizedBox(
width: 270,
child: Text(
data[index].title ?? "",
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 18,
color: Colors.grey,
fontWeight: FontWeight.bold,
),
),
),
)
I am developing an app where I need to maintain an add to cart session. I need to store the items in the local DB and retrieve the data from the local DB in another screen when the add to cart button is clicked. I have the data from the API in a list but I am not getting how to save those data in the database. Please help me solve the problem. Thank you
//This is the screen from wherein a button click I need to save the data to the local database.
home.dart
ClipRRect(
borderRadius:
BorderRadius.only(
bottomLeft:
Radius.circular(5.0),
bottomRight:
Radius.circular(5.0),
),
child: Container(
decoration: BoxDecoration(
border: Border(
right: BorderSide(
color: Colors.black12,
),
left: BorderSide(
color: Colors.black12,
),
bottom: BorderSide(
color: Colors.black12,
),
)),
height: 40.0,
width: 200.0,
child: ActionChip(
label: Text(
"ADD TO CART",
style: TextStyle(
fontSize: 16.0),
),
pressElevation: 0.0,
avatar: Icon(
Icons
.add_shopping_cart,
size: 20.0,
color: Color(
0xFFD1A155,
),
),
backgroundColor:
Colors.transparent,
onPressed: () async {
await DBProvider.db
.newClient(
clientList(
index));
}),
),
),
//This is how i am fetching the data from the api
List<FeaturedModel> myAllDatas = [];
List<FeaturedItemsModel> myItems = [];
Future getDatas() async {
String basicAuth = 'Basic ' +
base64.encode(
utf8.encode('${GlobalVar.consumerKey}:${GlobalVar.secretKey}'));
var response = await http
.get("${GlobalVar.url}wp-json/wc/v3/products?featured=1", headers: {
'Authorization': basicAuth,
'Accept': 'application/json',
});
if (response.statusCode == 200) {
String responseBody = response.body;
var jsonBody = json.decode(responseBody);
for (var data in jsonBody) {
myAllDatas.add(new FeaturedModel(
data['id'], data['name'], data['price'], data['average_rating']));
for (var items in jsonBody) {
myItems.add(new FeaturedItemsModel(items['images'][0]['src']));
}
}
setState(() {});
} else {
print(response.statusCode);
print(response.body);
}
}
model class
import 'dart:convert';
Client clientFromJson(String str) {
final jsonData = json.decode(str);
return Client.fromMap(jsonData);
}
String clientToJson(Client data) {
final dyn = data.toMap();
return json.encode(dyn);
}
class Client {
int id;
String name;
String price;
String category;
String image;
Client({this.id, this.name, this.price, this.category, this.image});
factory Client.fromMap(Map<String, dynamic> json) => new Client(
id: json["id"],
name: json["name"],
price: json["price"],
category: json["category"],
image: json["image"],
);
Map<String, dynamic> toMap() => {
"id": id,
"name": name,
"price": price,
"category": category,
"image": image
};
}
dbhelper class
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:restaurant_app/models/cartModel.dart';
import 'package:sqflite/sqflite.dart';
class DBProvider {
DBProvider._();
static final DBProvider db = DBProvider._();
Database _database;
Future<Database> get database async {
if (_database != null) return _database;
// if _database is null we instantiate it
_database = await initDB();
return _database;
}
initDB() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "TestDB.db");
return await openDatabase(path, version: 1, onOpen: (db) {},
onCreate: (Database db, int version) async {
await db.execute("CREATE TABLE Client ("
"id INTEGER PRIMARY KEY,"
"name TEXT,"
"price TEXT,"
"category TEXT,"
"image TEXT,"
")");
});
}
newClient(Client newClient) async {
final db = await database;
//get the biggest id in the table
var table = await db.rawQuery("SELECT MAX(id)+1 as id FROM Client");
int id = table.first["id"];
//insert to the table using the new id
var raw = await db.rawInsert(
"INSERT Into Client (id,first_name,last_name,blocked)"
" VALUES (?,?,?,?)",
[id, newClient.name, newClient.price,
newClient.category,newClient.image]);
return raw;
}
updateClient(Client newClient) async {
final db = await database;
var res = await db.update("Client", newClient.toMap(),
where: "id = ?", whereArgs: [newClient.id]);
return res;
}
getClient(int id) async {
final db = await database;
var res = await db.query("Client", where: "id = ?", whereArgs: [id]);
return res.isNotEmpty ? Client.fromMap(res.first) : null;
}
Future<List<Client>> getAllClients() async {
final db = await database;
var res = await db.query("Client");
List<Client> list =
res.isNotEmpty ? res.map((c) => Client.fromMap(c)).toList() : [];
return list;
}
deleteClient(int id) async {
final db = await database;
return db.delete("Client", where: "id = ?", whereArgs: [id]);
}
deleteAll() async {
final db = await database;
db.rawDelete("Delete * from Client");
}
}
Could you provide more details on what's not working in your implementation? The documentation in sqflite includes example for helpers that you can use.
Since you're mapping the json data into an Object, this helper snippet from the page should help map Objects in the database.
Future<Todo> insert(Todo todo) async {
todo.id = await db.insert(tableTodo, todo.toMap());
return todo;
}