Below output sample returning by the server which i should use Dart classes to create data class from them
const cities = """[
{
"id": 1,
"province_id": 1,
"name": "test1",
"neighborhood": []
},
{
"id": 2,
"province_id": 1,
"name": "test2",
"neighborhood": [
{"id": 1, "city_id": 1, "name": "xxx 1"},
{"id": 2, "city_id": 1, "name": "xxx 2"}
]
}
]
""";
as you can see cities is an Array and into that neighborhood is as array too
data class which i implemented for them:
#freezed
class City with _$City {
const factory City(
final int id,
#JsonKey(name: 'province_id') final int provinceId,
final String name,
final List<Neighborhood>? neighborhood,
) = _City;
factory City.fromJson(Map<String, dynamic> json) => _$CityFromJson(json);
}
#freezed
class Neighborhood with _$Neighborhood {
const factory Neighborhood(
final int id,
#JsonKey(name: 'city_id') final int cityId,
final String name,
) = _Neighborhood;
factory Neighborhood.fromJson(Map<String, dynamic> json) => _$NeighborhoodFromJson(json);
}
and now when i try to use this code to convert json data i get error:
final List<Map<String,dynamic>> data = json.decode(cities) as List<Map<String,dynamic>>;
final city = data.map((elements) => City.fromJson(elements)).toList();
Error:
The argument type 'Map<String, dynamic> Function(dynamic)' can't be assigned to the parameter type 'Iterable<dynamic>'.
You should be mapping the result like
final l = json.decode(cities);
List<City> city = l.map((elements) => City.fromJson(elements)).toList();
Related
I have data from API like this :
{
"data": {
"1": [
{
"id": 31,
"customer_id": 2,
"product_variant_id": 123,
"quantity": 5,
"partner_id": 1
},
{
"id": 30,
"customer_id": 2,
"product_variant_id": 109,
"quantity": 2,
"partner_id": 1
}
],
"3": [
{
"id": 29,
"customer_id": 2,
"product_variant_id": 107,
"quantity": 8,
"partner_id": 3,
}
]
},
"code": 200,
"msg": "Data All Cart"
}
and here's the cartModel :
class CartMetadata {
CartMetadata({
required this.data,
required this.code,
required this.msg,
});
final Map<String, List<CartModel>> data;
final int code;
final String msg;
factory CartMetadata.fromJson(Map<String, dynamic> json) => CartMetadata(
data: Map.from(json["data"]).map((k, v) => MapEntry<String, List<CartModel>>(k,
List<CartModel>.from(v.map((x) => CartModel.fromJson(x))))),
code: json["code"],
msg: json["msg"],
);
Map<String, dynamic> toJson() => {
"data": Map.from(data).map((k, v) => MapEntry<String, dynamic>(k,
List<dynamic>.from(v.map((x) => x.toJson())))),
"code": code,
"msg": msg,
};
}
class CartModel {
CartModel({
required this.id,
required this.customerId,
required this.productVariantId,
required this.quantity,
required this.partnerId,
});
final int id;
final int customerId;
final int productVariantId;
final int quantity;
final int partnerId;
factory CartModel.fromJson(Map<String, dynamic> json) => CartModel(
id: json["id"],
customerId: json["customer_id"],
productVariantId: json["product_variant_id"],
quantity: json["quantity"],
partnerId: json["partner_id"],
);
Map<String, dynamic> toJson() => {
"id": id,
"customer_id": customerId,
"product_variant_id": productVariantId,
"quantity": quantity,
"partner_id": partnerId,
};
}
I was using this variable :
final jsonMap = CartMetadata.fromJson(jsonDecode(response.body));
CartModel? cart;
And the result I need is specific data with specific id, example for id == 30 :
cart = { "id": 30, "customer_id": 2, "product_variant_id": 109,
"quantity": 2, "partner_id": 1 }
I know I should used 'where' function, but I already try and the problem I should use array on jsonMap.data[array].
Anyone can give advice?
Just use,
Way: 1 - use map and array
jsonMap.data["1"]?[1]
// "1" is key of data or partner_id
// 1 is index of array
// ? is for null safety
Way: 2 - Make extension
extension GetCartItem on CartMetadata {
CartModel? cartItem(int partnerId, int index){
return data["$partnerId"]?[index];
}
}
usage,
jsonMap.cartItem(1,1) // return CartItem or null, Don't forget to import extension :)
function calling
ElevatedButton(
onPressed: () {
findItem(30);
},
child: Text("click")),
Pass item id
findItem(int id) {
final cartMeta = CartMetadata.fromJson(json);
CartModel? data1;
cartMeta.data.forEach((key, value) {
value.forEach((element) {
if (element.id == id) data1 = element;
});
});
print("result ==> ${data1?.toJson()}");
}
Result ScreenShot
use
cart.toJson()
which is already written in your data class to get a json in that specified format
In my opinion just use cart.<variable_name> to access instead of doing same work multiple time json if you really need use the above wholde code will be
final jsonMap = CartMetadata.fromJson(jsonDecode(response.body));
CartModel? cart = jsonMap.data['1'].single; //1 is the key of the data and if you want specific cart use where condition or get through a index like [0] {int inside}
try this might help but also try other might also have more easy to follow
// put the data to your model e.g.
final converttoModel = CartMetadata.fromJson(jsondata);
then try to use entries and get the value data
final find = converttoModel.data.entries
.map((e)=> e.value)
.map((e) => e.where((e)=> e.id == 31)
.first.toJson());
// then print the data or log it on debug console
log(find.first.toString());
as the result data would get is id 31
{id: 31, customer_id: 2, product_variant_id: 123, quantity: 5, partner_id: 1}
I am new in Dart and Flutter.
I am trying to access and print certain information from local JSON file. Here is the structure of my myPet.json file:
{
"person":
[
{
"user_id": 23,
"user_name": "Joe Hann",
"user_dob": 1998,
"pets":
[
{
"id": 1,
"name": "Fifi",
"type": "Cat",
"attribute": ["Cute", "Black", "Caring"],
"likes":
{
"hobbies": ["Play Ball", "Outing", "Sleep"],
"food": ["Whiskas", "PowerCat", "Fried Fish"]
},
"dateAdopted": "2020-10-10 11:25:02.155"
},
{
"id": 2,
"name": "Dongo",
"type": "Dog",
"attribute": ["Ferocious", "Loyal", "Big"],
"likes":
{
"hobbies": ["Barking", "Eating", "Sleep"],
"food": ["Chicken", "Biscuit"]
},
"dateAdopted": "2020-8-10 8:10:09.392"
}
]
},
{
"user_id": 17,
"user_name": "Sam Doll",
"user_dob": 1995,
"pets":
[
{
"id": 13,
"name": "Gola",
"type": "Fish",
"attribute": ["Red", "Small", "Speeder"],
"likes":
{
"hobbies": ["Swimming", "Blurbing"],
"food": ["Bread", "PowerCat"]
},
"dateAdopted": "2021-2-20 11:00:08.165"
}
]
}
]
}
Here is my Dart code:
import "dart:convert"; //for json conversion
import "dart:io"; //for input output local file
void main() {
String jsonData = new File('myPet.json').readAsStringSync();
List<Person> _listPerson = [];
_listPerson = Person.allPersonFromJson(jsonData);
print("List of Person:-");
for(int i=0; i<_listPerson.length; i++)
{
print(_listPerson[i].user_id);
print(_listPerson[i].user_name);
print(_listPerson[i].user_dob);
print("");
print("Pets:");
for(int j =0;j<_listPerson[i].pet.length; j++)
{
print(_listPerson[i].pet[j].id);
print(_listPerson[i].pet[j].name);
print(_listPerson[i].pet[j].type);
print("Attributes:-");
for(int k=0;k<_listPerson[i].pet[j].attribute.length;k++)
{
print(_listPerson[i].pet[j].attribute[k]);
}
print("");
}
print("");
print("");
}
}
class Person{
final int user_id;
final String user_name;
final int user_dob;
final List<Pet> pet;
Person ({
required this.user_id,
required this.user_name,
required this.user_dob,
required this.pet});
static List<Person> allPersonFromJson(String jsonData) {
List<Person> person = [];
json.decode(jsonData)['person'].forEach((data) => person.add(_mapPerson(data)));
return person;
}
static Person _mapPerson(Map<String, dynamic> map){
final user_id = map['user_id'] as int?; //required but nullable int with exception
if (user_id == null) {throw UnsupportedError('Invalid data: $map -> "id" is missing');}
final user_name = map['user_name'] as String?; //required but nullable String with exception
if (user_name == null) {throw UnsupportedError('Invalid data: $map -> "name" is missing');}
final user_dob = map['user_dob'] as int;
final pet = Pet.allPetFromJson(map['pets']);
return new Person(
user_id: user_id,
user_name: user_name,
user_dob: user_dob,
pet: pet
);
}
Map<String, dynamic> toJson() {
return {
'user_id': user_id,
'user_name': user_name,
'user_dob': user_dob,
'pet': pet
};
}
}
class Pet{
final int id;
final String name;
final String type;
final List<String> attribute;
Pet ({
required this.id,
required this.name,
required this.type,
required this.attribute});
static List<Pet> allPetFromJson(String jsonData) {
List<Pet> pet = [];
json.decode(jsonData)['person']['pets'].forEach((data) => pet.add(_mapPet(data)));
return pet;
}
static Pet _mapPet(Map<String, dynamic> map){
final id = map['id'] as int?; //required but nullable int with exception
if (id == null) {throw UnsupportedError('Invalid data: $map -> "pet id" is missing');}
final name = map['name'] as String?; //required but nullable String with exception
if (name == null) {throw UnsupportedError('Invalid data: $map -> "pet name" is missing');}
final type = map['type'] as String?; //required but nullable String with exception
if (type == null) {throw UnsupportedError('Invalid data: $map -> "pet type" is missing');}
final attribute = List<String>.from(map['attribute']);
return new Pet(
id: id,
name: name,
type: type,
attribute: attribute
);
}
Map<String, dynamic> toJson() {
return {
'id': id,
'name': name,
'type': type,
'attribute': attribute
};
}
}
I am able to call and print the Pet information by directly access to Pet object without include it in Person Object. But what I want to do is try call and print the Pet Object via Person Object. However I get the error "type 'List' is not a subtype of type 'String'".
How can I do that for this case?
I dont know what do allPersonFromJson method but you need to parse String to Json to access data:
final json = await json.decode(string); // <-- in your case "jsonData"
And with json["person"] you have a List of persons ( List<dynamic> )
This is probably going to be a stupid question but I have a problem to understand how fromJson and toJson works.
In this case if I use a List I do like that:
class DataPerDaysInfo{
List<Product>? products;
DataPerDaysInfo({required this.products});
factory DataPerDaysInfo.fromJson(Map<String, dynamic> json) => DataPerDaysInfo(
products : json["products"] == null ? null: List<Product>.from(json["products"].map((x) => Product.fromJson(x))));
Map<String, dynamic> toJson() =>
{
"products": products == null
? null
: List<dynamic>.from(products!.map((x) => x.toJson())),
};
}
but if I need to use a map how can I do it?
class DataPerDaysInfo{
Map<String, List<Product>> mapper;
DataPerDaysInfo({required this.mapper});
}
Without having a json string given. It is hard to guess. But maybe this implementation helps you a little:
import 'dart:convert';
void main() {
var dpdi = DataPerDaysInfo.fromJson(jsonDecode(json));
print(dpdi.toJson());
}
final String json = '''
{
"catalog1": [
{"id": 1, "name": "first"},
{"id": 2, "name": "second"}
],
"catalog2": [
{"id": 1, "name": "first"},
{"id": 2, "name": "second"}
]
}
''';
class DataPerDaysInfo {
Map<String, List<Product>> mapper = {};
DataPerDaysInfo.fromJson(Map<String, dynamic> json) {
json.forEach((key, value) => mapper[key] = value
.map((val) => Product.fromJson(val))
.cast<Product>()
.toList(growable: false));
}
String toJson() {
return jsonEncode(mapper);
}
}
class Product {
final int id;
final String name;
Product.fromJson(Map<String, dynamic> json)
: id = json['id'],
name = json['name'];
#override
String toString() {
return 'id: $id, name: $name';
}
Map<String, dynamic> toJson() {
return {'id': id, 'name': name};
}
}
I want to convert my object into JSON so I implemented following code
import "package:behoove/models/product.dart";
class Order {
Product _product;
int _quantity;
int _id;
Order(this._product, this._quantity, this._id);
int get id => _id;
int get quantity => _quantity;
Product get product => _product;
double get orderPrice => _quantity * double.parse(_product.discountedPrice ?? _product.price);
Map<String, dynamic> toJson() => {
"id": _product.id.toString(),
"name": _product.name,
"price": _product.price,
"quantity": _quantity.toString(),
"attributes": {},
"conditions": []
};
}
JSON from app is
{id: 9, name: GoldStar Classic 032, price: 1200, quantity: 1, attributes: {}, conditions: []}}
Screenshot JSON from app
But JSON from DartPad is
{"id":"1","name":"Sabin","price":200,"quantity":3,"attributes":{},"conditions":[]}
Screenshot JSON from DartPad console
How can I get same output on my app. please help. Also why is it not similar on both DartPad and app?
Instead of calling .toJson() directly use jsonEncode() as in the example (you can run it in DartPad to see difference). Calling jsonEncode(order) will give you a properly formatted json.
import 'dart:convert';
void main() {
final obj = Order();
print(obj.toJson());
print(jsonEncode(obj));
}
class Order {
int id = 0;
int price = 100;
String name = 'asdf';
int quantity = 10;
Map<String, dynamic> toJson() => {
"id": id.toString(),
"name": name,
"price": price,
"quantity": quantity.toString(),
"attributes": {},
"conditions": []
};
}
Output:
// simple toJson that ommits quotation marks
{id: 0, name: asdf, price: 100, quantity: 10, attributes: {}, conditions: []}
// properly encoded json
{"id":"0","name":"asdf","price":100,"quantity":"10","attributes":{},"conditions":[]}
I would want to get the data for all "name" only from the array data.
I want to print(data['data']['name']);
But it returns this error:
Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'
But when I print(data['data']);, it will return all data from "data":
"data": [
{
"created_at": "2020-03-16 16:10:51",
"deleted_at": null,
"id": 2,
"is_active": 1,
"name": "Maybank",
"updated_at": "2020-03-16 16:18:06"
},
{
"created_at": "2020-03-16 16:27:37",
......
],
Call API Code
displayBanks(BuildContext context) async {
_callApi.refreshTokenApi(context);
var _addressUrl = '$_hostUrl/banks'; //API URL
final SharedPreferences prefs = await SharedPreferences.getInstance();
_accessToken = prefs.getString('access_token');
Response _response = await get(_addressUrl, headers: {
'Content-type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $_accessToken'
});
var data;
data = jsonDecode(_response.body);
if (_response.statusCode == 200) {
print(data['data']['name']);
return data;
}
else {
print(_response.statusCode);
}
}
SAMPLE JSON DATA FROM API URL:
{
"data": [
{
"created_at": "2020-03-16 16:10:51",
"deleted_at": null,
"id": 2,
"is_active": 1,
"name": "Maybank",
"updated_at": "2020-03-16 16:18:06"
},
{
"created_at": "2020-03-16 16:27:37",
"deleted_at": null,
"id": 3,
"is_active": 1,
"name": "India International Bank (Malaysia) Berhad",
"updated_at": "2020-03-16 16:27:37"
},
{
"created_at": "2020-03-16 16:27:37",
"deleted_at": null,
"id": 4,
"is_active": 1,
"name": "National Bank of Abu Dhabi Malaysia Berhad",
"updated_at": "2020-03-16 16:27:37"
}
],
"links": {
"first": "https://demo.local/api/banks?page=1",
"last": "https://demo.local/api/banks?page=1",
"next": null,
"prev": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"path": "https://demo.local/api/banks",
"per_page": 5,
"to": 3,
"total": 3
}
}
Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'
The exception message explains the issue clearly.
The property 'name' is inside an object which itself placed in an array. So you first decode the array. Then access each object using the index (0..n), then from each object, you can read the 'name' property.
Here you go
class MyData {
final List<Data> data;
MyData({this.data});
factory MyData.fromJson(Map<String, dynamic> json) {
return MyData(
data: json['data'] != null ? (json['data'] as List).map((i) => Data.fromJson(i)).toList() : null,
);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.data != null) {
data['data'] = this.data.map((v) => v.toJson()).toList();
}
return data;
}
}
class Data {
final String created_at;
final String deleted_at;
final int id;
final int is_active;
final String name;
final String updated_at;
Data({this.created_at, this.deleted_at, this.id, this.is_active, this.name, this.updated_at});
factory Data.fromJson(Map<String, dynamic> json) {
return Data(
created_at: json['created_at'],
deleted_at: json['deleted_at'],
id: json['id'],
is_active: json['is_active'],
name: json['name'],
updated_at: json['updated_at'],
);
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['created_at'] = this.created_at;
data['id'] = this.id;
data['is_active'] = this.is_active;
data['name'] = this.name;
data['updated_at'] = this.updated_at;
data['deleted_at'] = this.deleted_at;
return data;
}
}
The error makes sense. The 'data' attribute in your JSON is array. So, you'll have to pass index of the item to access 'name' attribute - something like - data['data'][0]['name'] to get 'Maybank'.
Ideally, you should have a class which creates the instance from the JSON. In this case, the code snippet will look like :
Banks banks = new Banks.fromJson(data)
Now, you can use sites like this to create a class definition (including.fromJson).