I use Dio to getting response, and this is my modeling classes:
import 'package:shoppingcenter/screens/homePage.dart';
class MALL {
late final int id;
late final String name;
late final String images;
MALL({required this.id, required this.name, required this.images});
factory MALL.fromJson(Map<String, dynamic> data) {
final id = data['id'];
final name = data['name'];
final images = data['images'];
return MALL(id: id, name: name, images: images);
}
}
class City {
final List<MALL> malls;
City({required this.malls});
factory City.fromJson(Map<String, dynamic> data) {
final mallData = data['malls'] as List<dynamic>?;
final malls = mallData != null ? mallData.map((mallData) => MALL.fromJson(mallData)).toList() : <MALL>[];
return City(malls: malls);
}
}
I get this error when I try to use my classes:
Error: Expected a value of type 'Map<String, dynamic>', but got one of type 'String'
My JSON is:
{
"malls": [
{
"id": 1,
"name": "city center",
"images": "city.jpg"
}
]
}
My response code:
Future<List<MALL>> get() async {
final dio = Dio();
var url = 'My URL';
Response response = await dio.get(url);
City api = City.fromJson(response.data);
return api.malls;
}
What should I do?
As I can see from your answers:
Your API doesn't return a JSON, it returns a HTML file. It tries to parse the html file with jsonDecode. Check your API with Postman, why it doesn't return a response in JSON format.
response.data is a String. You need to decode it to Map:
City api = City.fromJson(jsonDecode(response.data));
I receive an object from my payload data (which has to be a String) like this: {id: 24VQUCeGD4KnW6tvfhj8MJjuASk, event: user}. Since it is a string now, how can I access the key and value pair of both items in flutter from a String? I have tried creating a model class for it, making a Map again out of the String, decoding it back to json object but all failed. How can I get the key/value pair in a proper way?
Code:
await _notificationsPlugin.show(
id,
'New notification',
'You have received a new notification!',
notificationDetails,
payload: message.data.toString(), // the payload data has to be a string
);
When you press on the notification:
onSelectNotification: (String data) async {
//here is where I want to access the key/value pair of that String 'data'
// i tried something like this but failed
var someData = jsonEncode(jsonDecode(data));
var className = ClassName.fromJson(someData);
print(className.id);
.. but nothing prints
//... some logic
}
class ClassName {
ClassName({
this.id,
this.event,
});
String id;
String event;
ClassName.fromJson(Map<String, dynamic> json) {
id = json['id'];
user = json['event'];
}
}
Any form of help is appreciated!
try this:
import 'dart:convert';
void processData(String data) {
Map<String, dynamic> someData = jsonDecode(data);
var className = ClassName.fromJson(someData);
print(className.id);
}
class ClassName {
ClassName({
required this.id,
required this.user,
});
String id;
String user;
ClassName.fromJson(Map<String, dynamic> json) :
id = json['id'],
user = json['user'];
}
void main() {
processData("{\"id\": \"24VQUCeGD4KnW6tvfhj8MJjuASk\", \"user\": \"user\"}");
}
p.s it seems that your provided JSON has id and event keys but in your ClassName, you are reading id and user keys which doesn't exist.
it happens that the id string isn't delimited so, you may try to custom decode like:
Map<String, String> decodePayload(String eventData) {
final aString = eventData.substring(5, eventData.length - 1);
final parts = aString.split(', ');
final id = parts[0];
final event = parts[1].substring(7, );
return {'id': id, 'event':event};
}
It doesn't looks nice but it may works
I would like to return the first five value of name from the JSON response above
Future <List<UserModel>> fetchData() async {
final response =
await http.get(Uri.parse(URLCONST.API_URL));
if (response.statusCode == 200) {
List jsonResponse = json.decode(response.body);
return jsonResponse.map((user) => new UserModel.fromJson(user)).toList();
} else {
throw Exception('Unexpected error occured!');
}
}
Here's the model below.
class UserModel {
int id;
String name;
UserModel({
required this.id,
required this.name,
});
factory UserModel.fromJson(Map<String, dynamic> json) {
return UserModel(
id: json['id'],
name: json['name'],
);
}
}
API has several values in the list and I'd like to return the first 5 only
if i understood correctly, you can do something like this:
jsonResponse.map((user) => new UserModel
.fromJson(user))
// this will take only the first five elements of the iterable
.take(5)
// this will map each user to its corresponding name
.map((user) => user.name)
// this, as you already know, will convert the iterable to a list
.toList();
this will return a List<String> containing the first five names
I'm developing a web app using Flutter Web and RESTful API for backend.
So, I'm trying the fetch the data from the api, serialize it by using Flutter Models, then return the result.
The Problem is, I'm getting this result
Expected a value of type 'Map<String, dynamic>', but got one of type 'List<dynamic>'
How to fix this ?
Here's my flutter codes:
models
// To parse this JSON data, do
//
// final medicalRecordsModel = medicalRecordsModelFromJson(jsonString);
import 'dart:convert';
class MedicalRecordsModel {
MedicalRecordsModel({
this.id,
this.category,
this.fileName,
this.dateTimestamp,
this.description,
this.upload,
this.patientName,
this.age,
this.address,
this.userId,
this.patientId,
this.isActive,
});
final String id;
final String category;
final String fileName;
final String dateTimestamp;
final String description;
final String upload;
final String patientName;
final String age;
final String address;
final dynamic userId;
final int patientId;
final bool isActive;
factory MedicalRecordsModel.fromJson(Map<String, dynamic> json) {
return MedicalRecordsModel(
id: json["id"],
category: json["category"],
fileName: json["fileName"],
dateTimestamp: json["dateTimestamp"],
description: json["description"],
upload: json["upload"],
patientName: json["patientName"],
age: json["age"],
address: json["address"],
userId: json["userId"],
patientId: json["patientId"],
isActive: json["isActive"],
);
}
}
API Connection
import 'dart:convert';
import 'dart:developer';
import 'dart:async';
import 'package:app/src/constants/medical_records.dart';
import 'package:app/src/models/medical_records/medical_records.dart';
import 'package:app/src/pages/Medical-Records/medical_record.dart';
import 'package:http/http.dart' as http;
class MedicalRecordsManager {
var client = http.Client();
var url = ConstantMedicalRecords.medical_records_api;
Future<MedicalRecordsModel> getRecords() async {
var url = ConstantMedicalRecords.medical_records_api;
log('$url');
try {
final response = await client.get(url);
if (response.statusCode == 200) {
return MedicalRecordsModel.fromJson(jsonDecode(response.body));
// print(recordsModel);
}
} catch (Exception) {
print(Exception);
print("Error occured");
}
}
}
Here is the JSON data I want to get
{
"id": "103",
"category": "DOCUMENT",
"fileName": "Check Up",
"dateTimestamp": "2021-02-1012:59:46",
"description": "string",
"upload": "String",
"patientName": "1",
"age": "25",
"address": "Earth",
"userId": null,
"patientId": 12,
"isActive": true
}
Please help me with this one.
you can do it like that
MedicalRecordsModel.fromJson(jsonDecode(response.body) as Map<String, dynamic>);
change the getRecord as follows
Future<MedicalRecordsModel> getRecords() async {
var url = ConstantMedicalRecords.medical_records_api;
log('$url');
try {
final response = await client.get(url);
if (response.statusCode == 200) {
return MedicalRecordsModel.fromJson(jsonDecode(response.body)[0]);
// print(recordsModel);
}
} catch (Exception) {
print(Exception);
print("Error occured");
}
}
I think jsonDecode gives list of Maps therefore your json map is the first element of that list.
This code wiil work as you expected:
import 'package:json_helpers/json_helpers.dart';
void main() {
// responseBody is the same response.body
// When response is a list of objects
final list = responseBody1.jsonList((e) => MedicalRecordsModel.fromJson(e));
var obj = list[0];
print(obj.category);
print(obj.fileName);
// When response is an object
obj = responseBody2.json((e) => MedicalRecordsModel.fromJson(e));
print(obj.category);
print(obj.fileName);
}
final responseBody1 = '''
[
{
"id":"103",
"category":"DOCUMENT",
"fileName":"Check Up",
"dateTimestamp":"2021-02-1012:59:46",
"description":"string",
"upload":"String",
"patientName":"1",
"age":"25",
"address":"Earth",
"userId":null,
"patientId":12,
"isActive":true
}
]''';
final responseBody2 = '''
{
"id":"103",
"category":"DOCUMENT",
"fileName":"Check Up",
"dateTimestamp":"2021-02-1012:59:46",
"description":"string",
"upload":"String",
"patientName":"1",
"age":"25",
"address":"Earth",
"userId":null,
"patientId":12,
"isActive":true
}''';
class MedicalRecordsModel {
final String id;
final String category;
final String fileName;
final String dateTimestamp;
final String description;
final String upload;
final String patientName;
final String age;
final String address;
final dynamic userId;
final int patientId;
final bool isActive;
MedicalRecordsModel({
this.id,
this.category,
this.fileName,
this.dateTimestamp,
this.description,
this.upload,
this.patientName,
this.age,
this.address,
this.userId,
this.patientId,
this.isActive,
});
factory MedicalRecordsModel.fromJson(Map<String, dynamic> json) {
return MedicalRecordsModel(
id: json['id'] as String,
category: json['category'] as String,
fileName: json['fileName'] as String,
dateTimestamp: json['dateTimestamp'] as String,
description: json['description'] as String,
upload: json['upload'] as String,
patientName: json['patientName'] as String,
age: json['age'] as String,
address: json['address'] as String,
userId: json['userId'] as String,
patientId: json['patientId'] as int,
isActive: json['isActive'] as bool,
);
}
}
Output:
DOCUMENT
Check Up
DOCUMENT
Check Up
That is, when response is a list of objects:
final list = response.body.jsonList((e) => MedicalRecordsModel.fromJson(e));
When response is an object:
final object = response.body.json((e) => MedicalRecordsModel.fromJson(e));
If you don't know what the result is, then you can try both methods.
response.body.json((e) => Model.fromJson(e));
response.body.jsonList((e) => Model.fromJson(e));
If you have already decoded a JSON string and want to convert the result (or part of it), you can use the following methods:
If the type of the decoded value is Map:
final object = value.json((e) => Model.fromJson(e));
If the type of the decoded value is List:
final objects = value.json((e) => Model.fromJson(e));
Every response is sended and received as text, which can be converted to the
Map Format with the dart inbuilt core library import 'dart:convert';.
So the response from the request can be treated like this.
final res = await http.post(Uri.parse(url), body: json.encode({
'userId': uid,
'email': email,
}),
head body: json.encode({
'userId': uid,
'email': email,
}),
headers: {'Content-Type': 'application/json', 'token64': token});
here json.encode() is used to convert to String from Map.
now res variable contain the response which is also a string which can be convert to the Map with json.decode() like this.
final data = json.decode(res);
when working with the data sometimes we occur errors like Map is not a type of Map<String, String> etc.
Which can be solved by type casting the res, like this.
Map<String, String> notification = Map<String, String>.from(data['notification']);
I see these type casting method used in the The boring Flutter Development show in Youtube.
I faced the same kind of problem after I built an API and tried consuming it in flutter. I first extracted the data and check if the extracted data is null. When the condition is false, I made a list loadStudents that will hold the data after the loop. This is what worked out for me after a ton of stress looking for solutions online.
I want to convert a list of 'Box' objects to a json file and also read it back in (json file to a list a 'Box' objects), but I'm a bit stuck on the implementation. I have written the below code, but I can only write a single 'Box' object to the json and convert a single 'Box' object back. When I try to do this with a list I hit errors like data that gets overwritten or just a single object that gets returned.
So in short, I want to write a List to json and convert json to List
I have the following data structure
Box model
class Box {
final String nameBox;
final List<Item> items;
Box({#required this.nameBox, #required this.items});
factory Box.fromJson(Map<String, dynamic> json) {
var items = json['items'];
List<Item> itemsList = items.cast<Item>();
return new Box(
nameBox: json["nameBox"],
items: itemsList
);
}
Map<String, dynamic> toJson() => {
"nameBox": nameBox,
"items": items,
};
}
Box fromJson(String boxData) {
return Box.fromJson(json.decode(boxData));
}
String toJson(Box box) {
return json.encode(box.toJson());
}
Item model
class Item {
final String itemName;
final int quantity;
Item({#required this.itemName, #required this.quantity});
factory Item.fromJson(Map<String, dynamic> json) {
return new Item(itemName: json["itemName"], quantity: json["quantity"]);
}
Map<String, dynamic> toJson() => {
"itemName": itemName,
"quantity": quantity,
};
}
Item fromJson(String itemData) {
return Item.fromJson(json.decode(itemData));
}
String toJson(Item item) {
return json.encode(item.toJson());
}
writeToJson function
Future writeJson(Box box) async {
final file = await _localFile;
List<Box> tempRead = await returnBoxes();
if (tempRead.isEmpty || tempRead == null) {
return;
}
tempRead.add(box);
file.writeAsString(json.encode(tempRead));
}
readJson function
Future<List<Box>> returnBoxes() async {
final file = await _localFile;
List<Box> boxList = new List<Box>();
Map<String, dynamic> content = await json.decode(file.readAsStringSync());
boxList.add(Box.fromJson(content));
return boxList;
}
I also tried to cast the json content to a list, but then I hit some iterable errors. Any who can help me out?
JSON has this idiosyncrasy that everything is either an object or an array, and you don't know what you get until you decode it. Dart decodes the two json types into a Map<String, dynamic> and List<dynamic> respectively. (The reason that you get dynamic is because each of them could itself then be a value, a json array or a json object, recursively.)
Dart encodes a Dart object by calling toJson on it and a Dart list by emitting a [ then each member of the list then a ].
Knowing that, it's easy to encode and decode arrays/lists. (I removed all the unnecessary code.)
class Box {
final String nameBox;
final List<Item> items;
Box({#required this.nameBox, #required this.items});
factory Box.fromJson(Map<String, dynamic> json) => Box(
nameBox: json['nameBox'],
items: json['items'].map<Item>((e) => Item.fromJson(e)).toList(),
);
Map<String, dynamic> toJson() => {
'nameBox': nameBox,
'items': items,
};
}
class Item {
final String itemName;
final int quantity;
Item({#required this.itemName, #required this.quantity});
factory Item.fromJson(Map<String, dynamic> json) => Item(
itemName: json['itemName'],
quantity: json['quantity'],
);
Map<String, dynamic> toJson() => {
'itemName': itemName,
'quantity': quantity,
};
}
Future writeJson(Box box) async {
final file = await _localFile;
var boxes = await returnBoxes();
/* I think you probably don't want this...
if (boxes.isEmpty || boxes == null) {
return;
}*/
// but rather, this
if (boxes == null) boxes = [];
boxes.add(box);
await file.writeAsString(json.encode(boxes));
}
Future<List<Box>> returnBoxes() async {
final file = await _localFile;
// because the json is an array (i.e. enclosed in []) it will be decoded
// as a Dart List<dynamic>
List<dynamic> d = json.decode(await file.readAsString());
// here we map the List<dynamic> to a series of Box elements
// each dynamic is passed to the Box.fromJson constructor
// and the series is formed into a List by toList
return d.map<Box>((e) => Box.fromJson(e)).toList();
}