Parsing json array response / flutter - json

Did this according to this manual
https://www.bezkoder.com/dart-flutter-parse-json-string-array-to-object-list/
Dart/Flutter parse array of JSON objects into List
JSON that comes from the server
{"myChannels":[{"id":"2","name":"channel2test","imageUrl":"image1.png"},{"id":"2","name":"channel2test","imageUrl":"image2.png"}]}
Model Class
class ChannelModel {
String channelID;
String channelName;
String imageUrl;
ChannelModel(this.channelID, this.channelName, this.imageUrl);
factory ChannelModel.parsingChannels(dynamic json) {
return ChannelModel(json['channelID'] as String,
json['channelName'] as String, json['imageUrl'] as String);
}
#override
String toString() {
return '{ ${this.channelID}, ${this.channelName}, ${this.imageUrl} }';
}
}
Main block
try {
final response = await http.post(
url,
body: json.encode({
'action': 'getMyChannels',
'userID': userID,
'returnSecureToken': true,
}),
);
// print(jsonDecode(response.body));
var extractedData =
jsonDecode(response.body)['myChannels'] as List<dynamic>;
List<ChannelModel> channelObjects = extractedData
.map((cJson) => ChannelModel.parsingChannels(cJson))
.toList();
print(channelObjects);
channelObjects.forEach((Data) {
print('test');
});
the results is the following...
print(channelObjects) > outputs > []
print('test') > not working , channelObjects not looping

I would suggest serializing your response to dart classes. It would be much easier to access the data you want.
class ApiResponse {
ApiResponse({
required this.myChannels,
});
List<MyChannel> myChannels;
factory ApiResponse.fromJson(Map<String, dynamic> json) => ApiResponse(
myChannels: List<MyChannel>.from(
json["myChannels"].map((x) => MyChannel.fromJson(x)),
),
);
}
class MyChannel {
MyChannel({
required this.id,
required this.name,
required this.imageUrl,
});
String id;
String name;
String imageUrl;
factory MyChannel.fromJson(Map<String, dynamic> json) => MyChannel(
id: json["id"],
name: json["name"],
imageUrl: json["imageUrl"],
);
}
Then you can use it this way :
final extractedData = ApiResponse.fromJson(json.decode(response.body) as Map<String, dynamic>);
And access the data you want
extractedData.myChannels[0].id
extractedData.myChannels[0].name
extractedData.myChannels[0].imageUrl
for (var ch in extractedData.myChannels){
print(ch.id);
print(ch.name);
print(ch.imageUrl);
}

part 'example.g.dart';
#JsonSerializable()
class Channel{
final String id;
final String name;
final String? imageUrl;
Channel({required this.id, required this.name, this.imageUrl});
factory Channel.fromJson(Map<String, dynamic> json) => _$ChannelFromJson(json);
Map<String, dynamic> toJson() => _$ChannelToJson(this);
}
#JsonSerializable()
class ChannelList{
final List<Channel> myChannels;
ChannelList({required this.myChannels});
factory ChannelList.fromJson(Map<String, dynamic> json) => _$ChannelListFromJson(json);
Map<String, dynamic> toJson() => _$ChannelListToJson(this);
}
final extractedData = ChannelList.fromJson(json.decode(response.body));
https://pub.dev/packages/json_serializable
Using JsonSerializable more useful and understandable. You can read documentation of that package

Related

How do I get the value from nested locally stored json-file in Flutter?

I'm trying to get the nested values from my locally stored json file with Flutter.
I can get the "outer" values, but I haven't been able to get the "inner" ones. I have googled and searched here, but I still can't make it work, so any help is much appreciated.
I put the code in a sandbox to make it easier to see.
https://codesandbox.io/s/loving-thunder-meklbc?file=/lib/main.dart
If you rather look here this is what some files look like:
json:
[{
"id":184423,
"created":"2022-11-18T09:32:56.000Z",
"raw_data":[
{"measurement_id":18,"index":0,"substance":655,"pressure":20,"temperature":30.03},
{"measurement_id":18,"index":1,"substance":648,"pressure":38,"temperature":30.03},
{"measurement_id":18,"index":2,"substance":636,"pressure":90,"temperature":30.02},
{"measurement_id":18,"index":3,"substance":623,"pressure":130,"temperature":30.05},
{"measurement_id":18,"index":4,"substance":598,"pressure":147,"temperature":29.99}
]
},
{
"id":184423,
"created":"2022-11-19T09:32:56.000Z",
"raw_data":[
{"measurement_id":19,"index":0,"substance":586,"pressure":160,"temperature":30.05},
{"measurement_id":19,"index":1,"substance":564,"pressure":170,"temperature":29.99},
{"measurement_id":19,"index":2,"substance":553,"pressure":173,"temperature":30},
{"measurement_id":19,"index":3,"substance":544,"pressure":162,"temperature":30.02},
{"measurement_id":19,"index":4,"substance":538,"pressure":164,"temperature":30.01}
]
}
]
handler:
import 'dart:convert';
import 'package:flutter/services.dart' as rootbundle;
import '../model/usermodel.dart';
Future<List<UserModel>> readJsonData() async {
final jsondata = await rootbundle.rootBundle.loadString('/userdata.json');
final list = json.decode(jsondata) as List<dynamic>;
//print(list);
return list.map((e) => UserModel.fromJson(e)).toList();
}
model:
// ignore_for_file: non_constant_identifier_names
class UserModel {
late int? id, measurementId, index, substance, pressure;
late double? temperature;
UserModel(
this.id,
this.measurementId,
this.index,
this.substance,
this.pressure,
this.temperature,
);
UserModel.fromJson(Map<String, dynamic> json) {
id = json["id"];
measurementId = json['measurement_id'];
index = json['index'];
substance = json['substance'];
pressure = json['pressure'];
temperature = json['temperature'];
}
}
class UserModel {
UserModel(this.id, this.raw_data);
/// Creates a UserModel from Json map
factory UserModel.fromJson(Map<String, dynamic> json) => UserModel(
json['id'] as int?,
(json['raw_data'] as List<dynamic>?)
?.map((e) => Data.fromJson(e as Map<String, dynamic>))
.toList(),
);
final int? id;
final List<Data>? raw_data;
}
//Data
class Data {
Data(
this.measurement_id,
this.index,
this.substance,
this.pressure,
this.temperature,
);
final int? measurement_id;
final int? index;
final int? substance;
final int? pressure;
final double? temperature;
/// Creates a Data from Json map
factory Data.fromJson(Map<String, dynamic> json) => Data(
json['measurement_id'] as int?,
json['index'] as int?,
json['substance'] as int?,
json['pressure'] as int?,
(json['temperature'] as num?)?.toDouble(),
);
}
List<UserModel> models = [];
for (var item in list) {
models.addAll(item.map((e) => UserModel.fromJson(e['id'], e['raw_data'])));
}
return models;
UserModel.fromJson(int id, Map<String, dynamic> json) {
this.id = id; // parse json (raw_data)
}

Dart/Flutter : convert BigInt to json

I have an object with a bigint property i want to encode to json string:
class Token {
Token(
{
this.name,
this.supply,
});
String? name;
BigInt? supply;
factory Token.fromJson(Map<String, dynamic> json) {
return Token(
name: json['name'],
supply: json['supply'] == null ? null : BigInt.parse(json['supply']),
);
}
Map<String, dynamic> toJson() => <String, dynamic>{
'name': name,
'supply': supply == null ? null : supply!.toString(),
};
}
I create a method to encode json to string...
String tokenToJson(Token data) => jsonEncode(data.toJson())
... but the format is not correct because i need a bigint in the format json and not a string:
the result i want:
{"name":"Token","supply":100000000000000,}
the result i obtain:
{"name":"Token","supply":"100000000000000",}
jsonEncode doesn't manage bigint type and i found on internet only solutions with a conversion of the bigint to a string type.
NB: Same issue with jsonDecode
Thx
use this simple method instead of BigInt use just "num"
import 'dart:convert';
void main() {
String data = '''{"name":"Token","supply":100000000000000}''';
print("supply: ${Token.fromJson(jsonDecode(data)).supply}");
}
class Token {
Token({
required this.name,
required this.supply,
});
late final String name;
late final num supply;
Token.fromJson(Map<String, dynamic> json){
name = json['name'];
supply = json['supply'];
}
Map<String, dynamic> toJson() {
final _data = <String, dynamic>{};
_data['name'] = name;
_data['supply'] = supply;
return _data;
}
}
Please check the following answer, instead of calling toString method on supply just call toInt method which will prevents the quotations and you will get the formatted json as expected
import 'dart:convert';
class Token {
Token(
{
this.name,
this.supply,
});
String? name;
BigInt? supply;
factory Token.fromJson(Map<String, dynamic> json) {
return Token(
name: json['name'],
supply: json['supply'] == null ? null :BigInt.from(json['supply']) ,
);
}
Map<String, dynamic> toJson() => <String, dynamic>{
'name': name,
'supply': supply == null ? null : supply!.toInt(),
};
String tokenToJson(Token data) => json.encode(data.toJson());
}
void main() {
Token token = Token(name: "token_one",supply : BigInt.parse("10000061234567"));
print(token.tokenToJson(token));
}
Output
{"name":"token_one","supply":10000061234567}
You don't need to parse, you can use from for convert int to BigInt
import 'dart:convert';
void main() {
String data = '''{"name":"Token","supply":100000000000000}''';
print(Token.fromJson(jsonDecode(data)).toJson());
}
class Token {
String? name;
double? supply;
Token({this.name, this.supply});
Token.fromJson(Map<String, dynamic> json) {
name = json['name'];
supply = json['supply'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['name'] = name;
data['supply'] = supply;
return data;
}
}

Trying to parse a JSON file but it returns me _TypeError (type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String')

I'm trying to parse a remote json but I always get this error _TypeError (type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'String'), I tried to simplify as much as possible the examples because my model is a bit complex and the JSON has more than 5000 words.
Here's my function:
Future<void> updateCrypto(String symbol) async {
Uri url = Uri.https(); // url where I get the json
try {
final response = await http.get(url);
final parsedJson = json.decode(response.body) as Map<String, dynamic>;
final Cryptocurrency updatedCrypto = Cryptocurrency.fromJson(parsedJson);
} catch (error) {
throw (error);
}
}
My model:
class Cryptocurrency with ChangeNotifier {
Cryptocurrency({
required this.id,
required this.symbol,
required this.name,
...
});
late final String id;
late final String symbol;
late final String name;
...
factory Cryptocurrency.fromJson(Map<String, dynamic> json) {
return Cryptocurrency(
id: json['id'],
symbol: json['symbol'],
name: json['name'],
...
}
}
Json example (cut because it's a 5000 words json file):
{"id":"bitcoin","symbol":"btc","name":"Bitcoin", }
I like to modify the entity and use case like
import 'dart:convert';
class Cryptocurrency with ChangeNotifier {
final String id;
final String symbol;
final String name;
Cryptocurrency({
required this.id,
required this.symbol,
required this.name,
});
Map<String, dynamic> toMap() {
final result = <String, dynamic>{};
result.addAll({'id': id});
result.addAll({'symbol': symbol});
result.addAll({'name': name});
return result;
}
factory Cryptocurrency.fromMap(Map<String, dynamic> map) {
return Cryptocurrency(
id: map['id'] ?? '',
symbol: map['symbol'] ?? '',
name: map['name'] ?? '',
);
}
String toJson() => json.encode(toMap());
factory Cryptocurrency.fromJson(String source) =>
Cryptocurrency.fromMap(json.decode(source));
}
And use case
final response = await http.get(Uri.parse(url));
final parsedJson = json.decode(response.body);
if (response.statusCode == 200) {
final data = jsonDecode(response.body);
final Cryptocurrency updatedCrypto = Cryptocurrency.fromJson(data);

Flutter error: the argument type 'dynamic' can't be assigned to the parameter type 'Iterable<dynamic>'

Kindly assist.
I am attempting to create a model using the JSON to Dart tool https://app.quicktype.io/
The aim is to retrieve a list of all companies (with their properties) from a JSON API.
I am getting the below errors:
the argument type 'dynamic' can't be assigned to the parameter type Map<String, dynamic>
the argument type 'dynamic' can't be assigned to the parameter type Iterable
the argument type 'dynamic' can't be assigned to the parameter type Int
Please refer to the image below.
the argument type 'dynamic' can't be assigned to the parameter type...
Thank you.
I have tested this class and it works without errors
import 'dart:convert';
CompanyModel companyModelFromJson(String str) => CompanyModel.fromJson(json.decode(str));
String companyModelToJson(CompanyModel data) => json.encode(data.toJson());
class CompanyModel {
CompanyModel({
this.companies,
});
List<Company> companies;
factory CompanyModel.fromJson(Map<String, dynamic> json) => CompanyModel(
companies: List<Company>.from(json["companies"].map((x) => Company.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"companies": List<dynamic>.from(companies.map((x) => x.toJson())),
};
}
class Company {
Company({
this.id,
this.name,
});
int id;
String name;
factory Company.fromJson(Map<String, dynamic> json) => Company(
id: json["id"],
name: json["name"],
);
Map<String, dynamic> toJson() => {
"id": id,
"name": name,
};
}
As alternative you can use this code from JsonToDart
class CompanyModel {
List<Companies> companies;
CompanyModel({this.companies});
CompanyModel.fromJson(Map<String, dynamic> json) {
if (json['companies'] != null) {
companies = new List<Companies>();
json['companies'].forEach((v) {
companies.add(new Companies.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.companies != null) {
data['companies'] = this.companies.map((v) => v.toJson()).toList();
}
return data;
}
}
class Companies {
int id;
String name;
Companies({this.id, this.name});
Companies.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['name'] = this.name;
return data;
}
}

Error: type 'List<dynamic>' is not a subtype of type 'Map<String, dynamic>'

So I created an app to read data via api and I tried parsing the JSON api
this is my
Error screenshot
I've tried to change it to a list, but it still reads an error
this is my code
elephant.dart
#JsonSerializable()
class ElephantList{
ElephantList({this.biodata});
final List<Elephant> biodata;
factory ElephantList.fromJson(Map<String, dynamic> json) => _$ElephantListFromJson(json);
Map<String, dynamic> toJson() => _$ElephantListToJson(this);
}
#JsonSerializable()
class Elephant{
Elephant({this.name, this.affiliation, this.species,
this.sex, this.fictional, this.dob, this.dod, this.wikilink, this.image, this.note});
//final String index;
final String name;
final String affiliation;
final String species;
final String sex;
final String fictional;
final String dob;
final String dod;
final String wikilink;
final String image;
final String note;
factory Elephant.fromJson(Map<String, dynamic> json) => _$ElephantFromJson(json);
Map<String, dynamic> toJson() => _$ElephantToJson(this);
}
Future<ElephantList> getElephantList() async{
const url = 'https://elephant-api.herokuapp.com/elephants/sex/male';
final response = await http.get(url);
if(response.statusCode == 200){
return ElephantList.fromJson(json.decode(response.body));
}else{
throw HttpException('Error ${response.reasonPhrase}', uri: Uri.parse(url));
}
}
How do I rectify this error?
please help
The api : https://elephant-api.herokuapp.com/elephants/sex/male returns a List of elephants in the form : [Elephant , Elephant , ... ] while you're specifying that the json received from this request is a Map<String, dynamic> which have a form : { elephants : [ ... ] } so just replace every Map<String, dynamic> with List<dynamic>
#JsonSerializable(anyMap: true)
class ElephantList{
ElephantList({this.biodata});
final List<Elephant> biodata;
factory ElephantList.fromJson(List<dynamic> json) => _$ElephantListFromJson(json);
List<dynamic> toJson() => _$ElephantListToJson(this);
}
#JsonSerializable()
class Elephant{
Elephant({this.name, this.affiliation, this.species,
this.sex, this.fictional, this.dob, this.dod, this.wikilink, this.image, this.note});
//final String index;
final String name;
final String affiliation;
final String species;
final String sex;
final String fictional;
final String dob;
final String dod;
final String wikilink;
final String image;
final String note;
factory Elephant.fromJson(Map<String, dynamic> json) => _$ElephantFromJson(json);
Map<String, dynamic> toJson() => _$ElephantToJson(this);
}
Future<ElephantList> getElephantList() async{
const url = 'https://elephant-api.herokuapp.com/elephants/sex/male';
final response = await http.get(url);
if(response.statusCode == 200){
return ElephantList.fromJson(json.decode(response.body));
}else{
throw HttpException('Error ${response.reasonPhrase}', uri: Uri.parse(url));
}
}
Edit: #JsonSerializable expects the json as Map<string,dynamic>, so to change the expected type you should add anyMap: true
I changed the code accordingly