I do not understand how to parse a JSON file I get from firebase.
This is the format of the JSON file
{
"water" : {
"-MnRJkFC3--ZOTmpF1xN" : {
"milliliters" : 0.14,
"time" : "16:26:25"
},
"-MnRJkZRwZYEInHfSKIY" : {
"milliliters" : 48.83,
"time" : "16:26:25"
},
"-MnRJksES18hY765rxxq" : {
"milliliters" : 41.44,
"time" : "16:26:25"
},
"-MnRJlDn6o4RmiGRJS-E" : {
"milliliters" : 11.37,
"time" : "16:26:25"
}
}
}
This is how I am reading the JSON file
Future loadSalesData() async {
final String jsonString = await getJsonFromFirebase();
final dynamic jsonResponse = json.decode(jsonString);
for (Map<String, dynamic> i in jsonResponse)
chartData.add(SalesData.fromJson(i));
}
The getJsonFromFirebase() looks like this:
Future<String> getJsonFromFirebase() async {
String url =
"https://emailpassword. . .seio.com/water.json";
http.Response response = await http.get(Uri.parse(url));
return response.body;
}
When you click on the link it send you to the JSON file which looks like this
{
"-Mnbk2ye2P8bfpaQvNaU": {
"milliliters": 0.0,
"time": "18:07:00"
},
"-Mnbk6wd-wJze8P0JknK": {
"milliliters": 0.12,
"time": "18:07:00"
},
"-Mnbk7Ek629vgBu-MiLg": {
"milliliters": 44.91,
"time": "18:07:00"
},
"-Mnbk7bPuzqwsz9d5nm6": {
"milliliters": 5.43,
"time": "18:07:00"
},
"-Mnbk7v7MADi7YzEbeFI": {
"milliliters": 24.54,
"time": "18:07:00"
},
"-Mnbk8DGfqswckdsA1qP": {
"milliliters": 47.58,
"time": "18:07:00"
},
"-Mnbk8Xw2kJPxLrqCl6h": {
"milliliters": 13.98,
"time": "18:07:00"
}
}
I get the Error
_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Iterable'
With the shape of the JSON you are receiving, json.decode will return a Map<String, dynamic> (more specifically an instance of the _InternalLinkedHashMap<String, dynamic> specialisation). This type doesn't implement Iterable, so you can't iterate over it directly with the for-in construct, and this is the exact error you are getting, at run time.
Depending on what you need to construct your SalesData instance, you have two options:
iterate over the entries property, if you need the key of each item ("-Mnbk2ye2P8bfpaQvNaU", "-Mnbk6wd-wJze8P0JknK" etc), otherwise
iterate over the values property, if you don't
Entries
Iteration:
for (MapEntry<String, dynamic> i in jsonResponse.entries) {
chartData.add(SalesData.fromJson(i));
}
SalesData.fromJson:
SalesData.fromJson(MapEntry<String, dynamic> data) {
id = data.key;
milliliters = data.value['milliliters'];
time = data.value['time'];
}
Values
Iteration:
for (Map<String, dynamic> i in jsonResponse.values) {
chartData.add(SalesData.fromJson(i));
}
SalesData.fromJson:
SalesData.fromJson(Map<String, dynamic> data) {
milliliters = data['milliliters'];
time = data['time'];
}
Type Inference
Additionally, regardless of how you decide to iterate over the Map instance, you can clean up the code a little taking advantage of Dart's type inference, so (presuming you are iterating over the entries) loadSalesData could become:
Future loadSalesData() async {
final jsonString = await getJsonFromFirebase();
final jsonResponse = json.decode(jsonString);
for (final i in jsonResponse.entries) {
chartData.add(SalesData.fromJson(i));
}
}
and getJsonFromFirebase could become:
Future<String> getJsonFromFirebase() async {
final url = "http://localhost:8080/data.json";
final response = await http.get(Uri.parse(url));
return response.body;
}
It seems flutter does not understand that jsonResponse is an iterable because you defined it as dynamic.
Adjust the definition to tell flutter it is a map:
final Map<String, dynamic> jsonResponse = json.decode(jsonString);
Related
i call an api with
Future<ApiData> fetchData() async {
final response = await http
.get(Uri.parse(
'https://apilink.com'));
if (response.statusCode == 200) {
Map<String, dynamic> jsonResponse = json.decode(response.body);
return ApiData.fromJson(jsonDecode(response.body));
}
and have a json file like this:
{
"data": {
"base_data": {
"US": {
"org_data": {
"country_full_name": "UNITED STATES",
"size": "large"
},
"user_data": {
"amount": 1.0,
"owned_in_total_euro": 100
}
},
"DE": {
"org_data": {
"country_full_name": "Germany",
"size": "medium"
},
"user_data": {
"amount": 5.0,
"owned_in_total_euro": 400
}
}
},
"calc_data": {
"country": {
"United States": 1.0
"Germany": 5.0
"Poland": 4.5
},
"currency": {
"USD": 1.0
"EUR": 2.0
}
}
}
}
In jsonReponse is a map with 1 item => 0: "data" -> Map (2 items)
This is a map with maps inside with other maps or lists inside and they are dynamice like this:
Map
Map1
MapABC
MapXYZ
List
Map2
List
MapX
I tried a lot of things like this but nothing worked:
//data map
Map<String, dynamic> jsonResponse = json.decode(response.body);
//base_data & calc_data inside data
Map<dynamic, dynamic> jsonResponse2 = Map.from(jsonResponse);
Question:
How can I access this in flutter?
Do you have any examples of info on this for me?
I tryed a lot with stuff I found in google and the decode-help but can´t find out how to process a (dynamic)-map in a map.
Thanks in advance
Patrick
Update:
I added this to my model:
#JsonSerializable(explicitToJson: true)
class BackendCalcData {
List<BackendCalcDataCountry>? backendCountry;
List<BackendCalcDataCurrency>? backendCurrency;
BackendCalcData({
List<BackendCalcDataCountry>? backendCountry,
List<BackendCalcDataCurrency>? backendCurrency,
});
factory BackendCalcData.empty() {
return BackendCalcData();
}
factory BackendCalcData.fromJson(Map<String, dynamic> json) =>
_$BackendCalcDataFromJson(json);
Map<String, dynamic> toJson() => _$BackendCalcDataToJson(this);
}
#JsonSerializable()
class BackendCalcDataCountry {
String countryName;
double countryRatio;
BackendCalcDataCountry({
this.countryName = "",
this.countryRatio = 0,
});
factory BackendCalcDataCountry.fromJson(Map<String, dynamic> json) =>
_$BackendCalcDataCountryFromJson(json);
Map<String, dynamic> toJson() => _$BackendCalcDataCountryToJson(this);
}
#JsonSerializable()
class BackendCalcDataCurrency {
String currencyCode;
double currencyRatetoEuro;
BackendCalcDataCurrency({
this.currencyCode = "",
this.currencyRatetoEuro = 0,
});
factory BackendCalcDataCurrency.fromJson(Map<String, dynamic> json) =>
_$BackendCalcDataCurrencyFromJson(json);
Map<String, dynamic> toJson() => _$BackendCalcDataCurrencyToJson(this);
}
And got the generated code.
i have a problem with a json response
Json it's:
{
"SData": {
"total": "1",
"STable": {
"year": "2020",
"S1Lists": [
{
"year": "2020",
"turn": "6",
"Ranking": [
{
"position": "1",
"Person": {
"personId": "paul",
"nationality": "none"
},
},
]
}
]
}
}
Dart code
if(response.statusCode == 200){
final result = response.data;
Iterable list = result['SData'];
print(list);
}else{
throw Exception("Fail!");
}
and i receive this error
Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'Iterable<dynamic>'
how can i solve if, for example, i want to access the position field or the personId field
This happens because your json output is a Map<String, dynamic> and not a Iterable.
if (response.statusCode == 200) {
final result = response.data;
final Map<String, dynamic> map = result['SData'];
print(map );
} else {
throw Exception("Fail!");
}
Which will print this output
{
"total":1,
"STable":{
"year":2020,
"S1Lists":[
{
"year":2020,
"turn":6,
"Ranking":[
{
"position":1,
"Person":{
"personId":"paul",
"nationality":"none"
}
}
]
}
]
}
}
If you want to get the ranking.
final Map<String, dynamic> data = result ['SData'];
final Map<String, dynamic> table = data['STable']; // This is like result['SData']['STable']
final Map<String, dynamic> list = table['S1Lists']; // result['SData']['STable']['S1Lists']
final Map<String, dynamic> firstItem = list[0]; // result['SData']['STable']['S1Lists'][0]
final Map<String, dynamic> ranking = list['Ranking']; // result['SData']['STable']['S1Lists'][0]['Ranking']
Below is my json response, i want to get this response into model and nested model class. Please help me to read this json. Thanks in advance. I am new in flutter to parse json response in model class.
'''
{
"success": 1,
"totalResults": 5,
"data": [
{
"id": 1,
"bank_name": "SBI bank",
"bank_logo": "http://3.143.33.201/assets/banklogo/1/sbi-round-logo.png",
"bank_desc": "sbi",
"rating": "AA"
},
{
"id": 2,
"bank_name": "Yes bank",
"bank_logo": "http://3.143.33.201/assets/banklogo/2/yes-round-logo.png",
"bank_desc": "Yes bank",
"rating": "AA"
},
{
"id": 3,
"bank_name": "Union bank",
"bank_logo": "http://3.143.33.201/assets/banklogo/3/union-round-logo.png",
"bank_desc": "union bank",
"rating": "AA"
},
{
"id": 9,
"bank_name": "Bank of Baroda",
"bank_logo": "http://3.143.33.201/assets/banklogo/9/bob.png",
"bank_desc": "Bank of Baroda",
"rating": "AA"
},
{
"id": 10,
"bank_name": "IndusInd Bank",
"bank_logo": "http://3.143.33.201/assets/banklogo/10/Indus-bank-2.png",
"bank_desc": "IndusInd Bank",
"rating": "AA"
}
]
}
'''
We have a inbuilt package in dart for it,
dart:convert, the usage is as follows
import 'dart:convert' as convert;
...
// perform your http request and get the response from it,
var responseData = convert.jsonDecode(response.body);
convert.jsonDecode() will enable accessing the data stores in the responseData with key values.
#note : I have imported it as convert as for my convenience as I don't get confused while development.
Happy coding
You can use JSON and serialization for this
final _response = jsonDecode(jsonResponse);
After that you can use _response data in your model class like this
YourModel.fromJson(_response);
Initialize your model and use like this
final YourModel _yourModel = YourModel();
final _isSuccess = _yourModel.success;
final _data = _yourModel.data;
Step 1 >
Creat BankDataModel.dart
class BankDataModel {
int? success;
int? totalResults;
List<Data>? data;
BankDataModel({this.success, this.totalResults, this.data});
BankDataModel.fromJson(Map<String, dynamic> json) {
success = json['success'];
totalResults = json['totalResults'];
if (json['data'] != null) {
data = <Data>[];
json['data'].forEach((v) {
data!.add(new Data.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['success'] = this.success;
data['totalResults'] = this.totalResults;
if (this.data != null) {
data['data'] = this.data!.map((v) => v.toJson()).toList();
}
return data;
}
}
class Data {
int? id;
String? bankName;
String? bankLogo;
String? bankDesc;
String? rating;
Data({this.id, this.bankName, this.bankLogo, this.bankDesc, this.rating});
Data.fromJson(Map<String, dynamic> json) {
id = json['id'];
bankName = json['bank_name'];
bankLogo = json['bank_logo'];
bankDesc = json['bank_desc'];
rating = json['rating'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['bank_name'] = this.bankName;
data['bank_logo'] = this.bankLogo;
data['bank_desc'] = this.bankDesc;
data['rating'] = this.rating;
return data;
}
}
Step 2>
Crete Object you want use
BankDataModel _bankDataModel = BankDataModel();
Step 3>
Api call
Future<BankDataModel> getData() async {
BankDataModel _bankDataModel = BankDataModel();
final url = 'your-url';
try {
final response = await client.get(url);
if (response.statusCode == 200) {
_bankDataModel = BankDataModel.fromJson(response.data); < -- Here Json to BankDataModel Convert..
print(_bankDataModel.totalResults.toString()); < -- here print 5 as per question.
return _bankDataModel;
} else {
print(response.statusCode);
throw response.statusCode;
}
} catch (error) {
print(error);
}
}
Thanks you. Happy to help you.
in the angulardart tutorial, you can't find information on how to get data from a more complex json than in the example
link to the tutorial
json in brauser django rest framework
Content-Type: application/vnd.api+json
Vary: Accept
{
"data": [
{
"type": "Hero",
"id": "1",
"**attributes**": {
"name": "Windstorm"
}
},
{
"type": "Hero",
"id": "2",
"**attributes**": {
"name": "Bombasto"
}
},
{
"type": "Hero",
"id": "3",
"**attributes**": {
"name": "Magneta"
}
},
{
"type": "Hero",
"id": "4",
"**attributes**": {
"name": "Tornado"
}
}
]
}
hero.dart
//if you don't mind, use the tutorial example to show how to output data
class Hero {
final int id;
String name;
Hero(this.id, this.name);
factory Hero.fromJson(Map<String, dynamic> hero) =>
Hero(_toInt(hero['id']), hero['name']);
Map toJson() => {'id': id, 'name': name};
}
int _toInt(id) => id is int ? id : int.parse(id);
hero_service.dart
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart';
import 'hero.dart';
class HeroService {
static final _headers = {'Content-Type': 'application/json'};
static const _heroesUrl = 'http://127.0.0.1:8000/heroes'; // источник получения данных
final Client _http;
HeroService(this._http);
Future<List<Hero>> getAll() async {
try {
final response = await _http.get(_heroesUrl);
final heroes = (_extractData(response) as List)
.map((value) => Hero.fromJson(value))
.toList();
return heroes;
} catch (e) {
throw _handleError(e);
}
}
Future<Hero> create(String name) async {
try {
final response = await _http.post(_heroesUrl,
headers: _headers, body: json.encode({'name': name}));
return Hero.fromJson(_extractData(response));
} catch (e) {
throw _handleError(e);
}
}
dynamic _extractData(Response resp) => json.decode(resp.body)['data'];
Exception _handleError(dynamic e) {
print(e); // for demo purposes only
return Exception('Server error; cause: $e');
}
}
I don't get errors when working, he just can't get through to the characters...
Your "name" is down a level in the sample json inside of the **attributes** object .. so it would be:
class Hero {
final int id;
String name;
Hero(this.id, this.name);
factory Hero.fromJson(Map<String, dynamic> hero) =>
Hero(_toInt(hero['id']), hero['**attributes**']['name']);
Map toJson() => {'id': id, 'name': name};
}
int _toInt(id) => id is int ? id : int.parse(id);
It's important to not that any level of complexity of JSON can be represented in Dart through parent/child relationships of Map and/or List after being decoded.
Whenever I'm trying to fetch data it's throwing exception:
Exception has occurred.
NoSuchMethodError (NoSuchMethodError: The method 'map' was called on null.
Receiver: null
Tried calling: map<Location>(Closure: (dynamic) => Location))
print(responses) is printing null on console.
This is my function to get response from api:
String url1 = 'http://192.168.43.171:3000/location';
Future<void> showLocation() async {
var response = await http.get(Uri.encodeFull(url1));
if (response.statusCode == 200) {
print(response.body);
// Map<String, dynamic> parsedMap=jsonDecode(response.body);
final data = json.decode(response.body);
final responses = Details.fromJson(data[0]);
print(responses);
// print(parsedMap['location']);
} else {
throw Exception('failed to load');
}
}
This my locationModel.dart:
class Location {
final String latitude;
final String longitude;
Location({this.latitude, this.longitude});
factory Location.fromJson(Map<String, dynamic> parsedJson) {
return Location(
latitude: parsedJson['latitude'], longitude: parsedJson['longitude']);
}
}
class Details {
final String username;
final List<Location> locations;
Details({this.username, this.locations});
factory Details.fromJson(Map<String, dynamic> parsedJson) {
var list = parsedJson['locations'] as List;
print(list.runtimeType);
List<Location> locationList =
list.map((i) => Location.fromJson(i)).toList();
return Details(username: parsedJson['username'], locations: locationList);
}
}
My JSON:
[
{
"id":"ABC",
"username":"xyz",
"location":[
{
"latitude": "34",
"longitude": "343"
},
{
"latitude": "34",
"longitude": "32"
}
]
}
{
"id":"ABC1",
"username":"xyz1",
"location":[
{
"latitude": "34222",
"longitude": "32243"
},
]
}
]
You have a typo:
var list = parsedJson['locations'] as List;
vs
location:[
locations != location