Related
I am trying to build an application in which I want to show some data in a chart. I'm fetching my data from a database, and want to structure it for use in a FutureBuilder widget and then render a line chart with multiple lines using syncfusion_flutter_charts: ^20.1.61.
In the method where I try to structure my data in a list, so I can display multiple lines, I get the following error:
[ERROR:flutter/shell/common/shell.cc(93)] Dart Unhandled Exception: type 'Blob' is not a subtype of type 'String', stack trace: #0
I tried casting the scores[i]['name'] as a String, which didn't help. I guess I have a hard time understanding what the Blob type is and why it occurs.
Code below - and methods for database calls and fetching my data is below that. Added a comment on the line where the exception happens. Any help is greatly appreciated.
import 'database.dart';
import 'package:flutter/material.dart';
import 'package:syncfusion_flutter_charts/charts.dart';
import 'package:syncfusion_flutter_charts/sparkcharts.dart';
class BanditData {
BanditData(this.name, this.date, this.score);
final String name;
final String date;
final int score;
}
class MyStatsPage extends StatefulWidget {
const MyStatsPage({Key? key}) : super(key: key);
#override
MyStatsPageState createState() {
return MyStatsPageState();
}
}
class MyStatsPageState extends State<MyStatsPage> {
final database = Database();
Future<List<List<BanditData>>> getBanditData() async {
var dates = await database.getDistinctDatesList();
var scores = await database.createScoreDataStruct();
var bandits = await database.getBandits();
List<List<BanditData>> banditData = [];
for (var item in bandits) {
List<BanditData> temp = [];
for (var i = 0; i < scores.length; i++) { /* <--- Exception happens on this line */
BanditData bandit =
BanditData(scores[i]['name'], dates[i], scores[i]['score'][i]);
temp.add(bandit);
}
banditData.add(temp);
}
print(banditData);
return banditData;
}
#override
Widget build(BuildContext context) {
const appTitle = "Stats";
return Scaffold(
appBar: AppBar(
title: const Text(
appTitle,
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w700),
)),
body: FutureBuilder(
future: getBanditData(),
builder: (context, AsyncSnapshot<List<dynamic>> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
if (snapshot.hasError) {
return ErrorWidget(Exception(
'Error occured when fetching data from database'));
} else if (!snapshot.hasData) {
return const Center(child: Text('No data found.'));
} else {
final _scores = snapshot.data![0];
final _dates = snapshot.data![1];
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Expanded(
child: SfCartesianChart(
primaryXAxis: CategoryAxis(),
series: const <ChartSeries>[
/* Line charts here, when the data structure works */
],
))
],
);
}
}
}));
}
}
Database code:
import 'dart:async';
import 'package:intl/intl.dart';
import 'package:mysql1/mysql1.dart';
class Database {
final dateFormat = DateFormat('yyyy-MM-dd');
Future<MySqlConnection> connect() async {
var settings = ConnectionSettings(
/* REMOVED */
);
var conn = await MySqlConnection.connect(settings);
return conn;
}
Future<List<Map<String, dynamic>>> getBandits() async {
List<Map<String, dynamic>> items = <Map<String, dynamic>>[];
dynamic conn = await connect();
var results = await conn.query('select * from bandit');
for (var row in results) {
items.add({'value': row["ID"], 'label': row["bandit"]});
}
await conn.close();
return items;
}
void insertScore(id, date, course, score) async {
dynamic conn = await connect();
String query1 =
"insert into test_score (Bandit_ID, Bane, dato, Scores) values (?, ?, ?, ?)";
await conn.query(query1, [id, course, date, score]);
conn.close();
}
Future<void> updateDbActive1(id) async {
Future.delayed(const Duration(milliseconds: 500), () async {
dynamic conn = await connect();
String query = "UPDATE test_score SET IkkeAktiv = 1 WHERE Bandit_ID = ?";
await conn.query(query, [id]);
conn.close();
});
}
Future<void> updateDbActive2(id) async {
Future.delayed(const Duration(milliseconds: 500), () async {
dynamic conn = await connect();
String query =
"UPDATE test_score SET IkkeAktiv = 0 WHERE Bandit_ID = ? ORDER BY Scores DESC LIMIT 10";
await conn.query(query, [id]);
conn.close();
});
}
Future<List<String>> getDistinctDatesList() async {
List<String> dates = [];
dynamic conn = await connect();
String query =
"SELECT DISTINCT dato FROM test_score WHERE IkkeAktiv = 0 ORDER BY dato ASC";
var result = await conn.query(query);
for (var row in result) {
dates.add(dateFormat.format(row["dato"]).toString());
}
conn.close();
return dates;
}
Future<List<int>> getPlayerScoreFromDate(id) async {
dynamic conn = await connect();
var dateList = await getDistinctDatesList();
var scores = <int>[];
String query =
"SELECT * FROM test_score WHERE Bandit_ID = ? AND IkkeAktiv = 0 ORDER BY dato ASC";
var result = await conn.query(query, [id]);
var score = 0;
for (var date in dateList) {
var count = 0;
for (var row in result) {
if (date == dateFormat.format(row["dato"]).toString()) {
var value = row["Scores"];
score += value as int;
scores.add(score);
break;
} else {
count++;
if (count == result.length) {
scores.add(score);
}
continue;
}
}
}
conn.close();
return scores;
}
Future<List<Map<String, dynamic>>> createScoreDataStruct() async {
List<Map<String, dynamic>> playerScoresSum = <Map<String, dynamic>>[];
var bandits = await getBandits();
for (var bandit in bandits) {
playerScoresSum.add({
'value': bandit['value'],
'name': bandit['label'],
'scores': await getPlayerScoreFromDate(bandit['value'])
});
}
return playerScoresSum;
}
}
Seems like it could be fixed by adding .toString() in the method that fetches the data from the database.
Future<List<Map<String, dynamic>>> createScoreDataStruct() async {
List<Map<String, dynamic>> playerScoresSum = <Map<String, dynamic>>[];
var bandits = await getBandits();
for (var bandit in bandits) {
playerScoresSum.add({
'value': bandit['value'],
'name': bandit['label'].toString(), // <------
'scores': await getPlayerScoreFromDate(bandit['value'])
});
}
print(playerScoresSum);
return playerScoresSum;
}
I Have a problem to take the newest data index
class User {
final String idUser,
name,
phone;
User(
{this.idUser,
this.name,
this.phone});
factory User.fromJson(Map<String, dynamic> json) {
return User(
idUser: json['_id'],
name: json['name'],
phone: json['phone']);
}
}
List<User> userFromJson(jsonData) {
List<User> result =
List<User>.from(jsonData.map((item) => User.fromJson(item)));
return result;
}
// index
Future<List<User>> fetchUser() async {
String route = AppConfig.API_ENDPOINT + "userdata";
final response = await http.get(route);
if (response.statusCode == 200) {
var jsonResp = json.decode(response.body);
return userFromJson(jsonResp);
} else {
throw Exception('Failed load $route, status : ${response.statusCode}');
}
}
and the calling method just like this
user = fetchUser();
the "response.body" valued like this
[{"_id":"4136425eb8d9320f4822c554","name":"John","phone":"90643755394"},{"_id":"62766b2eb45s3w0g4662ftd3","name":"Anna","timestamp":"90345765791"}]
I expect it was how to take the first index to get the newest data, but I don't know ho the code will be. Also if there are another soltion to get that newest data, please let me know, thank you very much
Use index to get the specific value from a list
userFromJson(jsonResp[0]); /// For first record
You can use array index number to get the first object in array.
if (response.statusCode == 200) {
var jsonResp = json.decode(response.body);
return List<User>.from(jsonResp.map((user) => User.fromJson(user)));
} else {
throw Exception('Failed load $route, status : ${response.statusCode}');
}
If you want to get one user only
if (response.statusCode == 200) {
var jsonResp = json.decode(response.body);
return User.fromJson(jsonResp[0]);
} else {
throw Exception('Failed load $route, status : ${response.statusCode}');
}
Other method is by modifying the Query using LIMIT 1
Because its Future You have to use the await keyword to get the completed result so modify your code by adding await
users = await fetchUser();
now you can access the user list
var firstUser = users.first;
var firstUser = users[0];
For more await and async you can read this Asynchronous programming
Am trying to get a data from a json url but i get the error
Unhandled Exception: type 'List' is not a subtype of type 'SubJsonModel'
main.dart
final String url = 'https://raw.githubusercontent.com/BrightCode1/ohms-json/master/categories.json';
List<JsonModel> myModel = [];
#override
void initState() {
// TODO: implement initState
super.initState();
loadData();
}
loadData() async {
var res = await http.get(url, headers: {"Accept":"application/json"});
if(res.statusCode == 200) {
String resBody = res.body;
var jsonDecode = json.decode(resBody);
for(var data in jsonDecode) {
myModel.add(JsonModel(data['cat_id'], data['category'], data['cat_subcategory']));
setState(() {});
}
print(myModel[1].subCat.name);
}else {
print("Something went wrong!");
}
}
model.dart
class JsonModel {
final String id;
final String category;
SubJsonModel subCat;
JsonModel(this.id, this.category, this.subCat);
}
class SubJsonModel {
final String name;
final String image;
SubJsonModel(this.name, this.image);
}
please how do i solve this
So here what I do first create a model class with the help of this online tool. And then changed code like first save subcategory in one list and then passed it to the main list and then print
Here is my loadData() method
final String url =
'https://raw.githubusercontent.com/BrightCode1/ohms-json/master/categories.json';
List myModel = [];
loadData() async {
var res = await http.get(url, headers: {"Accept": "application/json"});
if (res.statusCode == 200) {
String resBody = res.body;
var jsonDecode = json.decode(resBody);
for (var data in jsonDecode) {
List<CatSubcategory> subCate = []; // Set a emoty list of CatSubcategory
data['cat_subcategory'].map((x) { // Here parsed the cat_subcategory data and simply add it into list
return subCate.add(
CatSubcategory(subName: x['sub_name'], subImage: x['sub_image']));
}).toList(); // and this done for we get map data so convert this data toList();
myModel.add(JsonModel(
category: data['category'],
catId: data['cat_id'],
catIcon: data['cat_icon'],
catSubcategory: subCate));
setState(() {});
}
print(myModel[0].catSubcategory[0].subName);
} else {
print("Something went wrong!");
}
}
here is my model class
class JsonModel {
JsonModel({
this.category,
this.catId,
this.catIcon,
this.catSubcategory,
});
String category;
String catId;
String catIcon;
List<CatSubcategory> catSubcategory;
factory JsonModel.fromJson(Map<String, dynamic> json) => JsonModel(
category: json["category"],
catId: json["cat_id"],
catIcon: json["cat_icon"],
catSubcategory: List<CatSubcategory>.from(
json["cat_subcategory"].map((x) => CatSubcategory.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"category": category,
"cat_id": catId,
"cat_icon": catIcon,
"cat_subcategory":
List<dynamic>.from(catSubcategory.map((x) => x.toJson())),
};
}
class CatSubcategory {
CatSubcategory({
this.subName,
this.subImage,
});
String subName;
String subImage;
factory CatSubcategory.fromJson(Map<String, dynamic> json) => CatSubcategory(
subName: json["sub_name"],
subImage: json["sub_image"],
);
Map<String, dynamic> toJson() => {
"sub_name": subName,
"sub_image": subImage,
};
}
You can use https://app.quicktype.io/ to create the model.dart from a json.
To parse this JSON data, do
final pieSingleChartInfo = pieSingleChartInfoFromJson(jsonString);
import 'dart:convert';
List<PieSingleChartInfo> pieSingleChartInfoFromJson(String str) => List<PieSingleChartInfo>.from(json.decode(str).map((x) => PieSingleChartInfo.fromJson(x)));
String pieSingleChartInfoToJson(List<PieSingleChartInfo> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class PieSingleChartInfo {
PieSingleChartInfo({
this.category,
this.catId,
this.catIcon,
this.catSubcategory,
});
String category;
String catId;
String catIcon;
List<CatSubcategory> catSubcategory;
factory PieSingleChartInfo.fromJson(Map<String, dynamic> json) => PieSingleChartInfo(
category: json["category"],
catId: json["cat_id"],
catIcon: json["cat_icon"] == null ? null : json["cat_icon"],
catSubcategory: List<CatSubcategory>.from(json["cat_subcategory"].map((x) => CatSubcategory.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"category": category,
"cat_id": catId,
"cat_icon": catIcon == null ? null : catIcon,
"cat_subcategory": List<dynamic>.from(catSubcategory.map((x) => x.toJson())),
};
}
class CatSubcategory {
CatSubcategory({
this.subName,
this.subImage,
});
String subName;
String subImage;
factory CatSubcategory.fromJson(Map<String, dynamic> json) => CatSubcategory(
subName: json["sub_name"],
subImage: json["sub_image"],
);
Map<String, dynamic> toJson() => {
"sub_name": subName,
"sub_image": subImage,
};
}
I noted a few issues and corrected them based on the information you provided.
Read the comments. Add a sample response body to the question.
final String url =
'https://raw.githubusercontent.com/BrightCode1/ohms-json/master/categories.json';
List<JsonModel> myModel = [];
#override
void initState() {
// TODO: implement initState
super.initState();
loadData();
}
loadData() async {
var res = await http.get(url, headers: {"Accept": "application/json"});
if (res.statusCode == 200) {
String resBody = res.body;
var jsonDecode = json.decode(resBody);
for (var data in jsonDecode) {
// first create SubJsonModel object
var subCat = SubJsonModel(
data['cat_subcategory']['name'], data['cat_subcategory']['image']);
//use subCat to create JsonModel
myModel.add(JsonModel(data['cat_id'], data['category'], subCat));
setState(() {});
}
print(myModel[1].subCat.name);
} else {
print("Something went wrong!");
}
}
I need to pass json data into my http APIs. I am not able to find the right way to do this yet. Here's my code snippet:
For all interactions to/from API, I have created an Dbhelper class.
Here's my Dbhelper class
class Dbhelper {
String fbody; // json parameter
Map result; // Response json for the api called
Dbhelper({this.fbody});
Future<void> executeData() async {
try {
//Make post request
Response response = await post('http://<my domain>/api/GetInfo',headers: {"content-type":"application/json"},body: $fbody);
var deviceinfo = jsonDecode(response.body);
print('In dbhelper $deviceinfo');
result = deviceinfo;
} catch(e) {
print('Something occured $e');
result = null;
}
}
}
This is what i am trying to do. I have login class which takes input from UI - UserName and password and need to pass this into Dbhelper object.
the intended json to be passed in my API is :
{
"strjson":{ "cUserName":"sandy" , "cPassword":"12345" },
"strSPName":"App_Userlogin"
}
toMap(String u, String p ){
return {
"strSPName":"App_userregister",
"strjson":{
"cUserName":u,
"cPassword":p
}
};
}
void _checkLogin(String u , String p) async {
try {
Map inputs = toMap(u,p);
print(inputs);
Dbhelper db = Dbhelper(fbody: inputs);
await db.executeData();
User user = User.fromJson(db.result);
if (user.uid >0)
Navigator.of(context).pushReplacementNamed('home');
else
print("User not found");
}catch(e){
print(e.toString());
User user = User(uid:0,username:'',userbalance: 0);
}
}
Please help me what I am missing in this
While passing body to http.post request . Try passing body inside single quotes.
Response response = await post('http://<my domain>/api/GetInfo',headers: {"content-type":"application/json"},body: '$fbody');
If this doesn't work, you can try encoding your body in json format using jsonEncode as shown
body: jsonEncode(<String, String> {'uname':'SomeName',})
Hope this works!
Json that I have posted in body..
{
"user": {
"UserName": "username",
"password": "password",
"Name": "name",
"Email": "email"
}
}
Your Post Api call be like:
Future<User> postUser(String username, String password, String name, String
email) async {
Paste your api url here
String url = '';
final response = await http.post(apiUrl, headers: {
// Enter your headers parameter if needed
// E.g:
'Authorization' : 'xyz',
'Content-Type' : 'application/json'
},
body: jsonEncode(<String, String>{
'UserName' : username,
'password' : password,
'Name' : name,
'Email' : email
}));
if (response.statusCode == 200) {
var data = jsonDecode(response.body.toString());
print(data);
return User.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to post user.');
}
}
Your model be like:
class User {
User? user;
User({this.user});
User.fromJson(Map<String, dynamic> json) {
user = json['user'] != null ? new User.fromJson(json['user']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.user != null) {
data['user'] = this.user!.toJson();
}
return data;
}
}
class User {
String? userName;
String? password;
String? name;
String? email;
User({this.userName, this.password, this.name, this.email});
User.fromJson(Map<String, dynamic> json) {
userName = json['UserName'];
password = json['password'];
name = json['Name'];
email = json['Email'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['UserName'] = this.userName;
data['password'] = this.password;
data['Name'] = this.name;
data['Email'] = this.email;
return data;
}
}
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;
}