How to access JSON nested data in flutter dart - json

I have the below json data, wherein I want to access the values inside the feeling_percentage.
{
"status": "200",
"data": {
"feeling_percentage": {
"Happy": "0",
"Sad": "0",
"Energetic": "0",
"Calm": "0",
"Angry": "0",
"Bored": "0"
},
}
}
I am able to fetch it using the below API code
Future<List<Data>> makePostRequest() async {
List<Data> list = [];
final uri = Uri.parse('<api>');
final headers = {'Content-Type': 'application/json', 'X-Api-Key':'<api_key>'};
Map<String, dynamic> body = {'user_id': 3206161992, 'feeling_date': '15-04-2022'};
String jsonBody = json.encode(body);
final encoding = Encoding.getByName('utf-8');
Response response = await post(
uri,
headers: headers,
body: jsonBody,
encoding: encoding,
);
int statusCode = response.statusCode;
String responseBody = response.body;
print('response body'+ responseBody);
}
After reading few articles, still not able to figure out how do I access the percentage of happy, sad inside the feeling_percentage.
I have created the model as
class Data{
FeelingPercentage feelingPercentage;
Data(
{required this.feelingPercentage});
factory Data.fromJson(Map<String, dynamic> json) {
return Data(
feelingPercentage: FeelingPercentage.fromJson(json["data"]),
);
}
}
class FeelingPercentage {
String? happy;
String? sad;
String? energetic;
String? calm;
String? angry;
String? bored;
FeelingPercentage({this.happy, this.sad, this.energetic, this.calm, this.angry, this.bored});
factory FeelingPercentage.fromJson(Map<String, dynamic> json) {
return FeelingPercentage(
happy: json["happy"] as String,
sad: json["sad"] as String,
energetic: json["energetic"] as String,
calm: json["calm"] as String,
angry: json["angry"] as String,
bored: json["bored"] as String,
);
}
}

Another way:
import 'package:fast_json/fast_json_selector.dart' as parser;
void main() {
final path = '{}.data.{}.feeling_percentage';
final level = path.split('.').length;
void select(parser.JsonSelectorEvent event) {
final levels = event.levels;
if (levels.length == level && levels.join('.') == path) {
print(event.lastValue);
event.lastValue = null;
}
}
parser.parse(_source, select: select);
}
const _source = '''
{
"status": "200",
"data": {
"feeling_percentage": {
"Happy": "0",
"Sad": "0",
"Energetic": "0",
"Calm": "0",
"Angry": "0",
"Bored": "0"
}
}
}''';
Output:
{Happy: 0, Sad: 0, Energetic: 0, Calm: 0, Angry: 0, Bored: 0}

You can use this website to convert your JSON object to a dart class.
it automatically creates the fromJson function, which can be used to pass JSON and receive the Dart objects.

Change this line in your model feelingPercentage: FeelingPercentage.fromJson(json["data"]), to feelingPercentage: FeelingPercentage.fromJson(json["data"]["feeling_percentage"]),
This will fix your issue.

You can do a JSON decode that will will result in a map, and then do the assigned like you are doing on your from Json factory, but as another constructor instead:
Class
Todo.fromMap(Map map) :
this.title = map['title'],
this.completed = map['completed'];
In use
Todo.fromMap(json.decode(item))

First decode response.body, then create FeelingPercentage object from json["data"]["feeling_percentage"] map.
Future<FeelingPercentage> makePostRequest() async {
...
final json = json.decode(response.body);
return FeelingPercentage.fromJson(json["data"]["feeling_percentage"])
}
class FeelingPercentage {
String? happy;
String? sad;
String? energetic;
String? calm;
String? angry;
String? bored;
FeelingPercentage({this.happy, this.sad, this.energetic, this.calm, this.angry, this.bored});
factory FeelingPercentage.fromJson(Map<String, dynamic> json) {
return FeelingPercentage(
happy: json["Happy"] as String,
sad: json["Sad"] as String,
energetic: json["Energetic"] as String,
calm: json["Calm"] as String,
angry: json["Angry"] as String,
bored: json["Bored"] as String,
);
}
}

Related

Flutter - How to convert Map<String, String> from TextEditingController to a Map<String, dynamic> JSON

I have about 40 TextFormFields and I retrieve their values with TextEditingController. The values are converted into a Map<String, String> map via the following step:
// map that stores controllers
Map<String, TextEditingController> storeControllers = controllers;
// convert to map that stores only controller texts
Map<String, String> currentSelections = storeControllers
.map((key, value) => MapEntry(key, storeControllers[key]!.text))
The current output with all values in String type:
//currentSelections map
Map<String, String>
{
"field1": "1",
"field2": "Two",
"field3": "0.03",
...
"field40": "four40",
}
How do I convert the currentSelections map into a JSON that stores the values in their corresponding types?
//Desired output:
Map<String, dynamic>
{
"field1": 1, //int
"field2": "Two", //String
"field3": 0.03, //double
...
"field40": "four40", //String
}
Any help would be appreciated! :)
I understand that the way to convert Strings to other types is using int.parse("text") method. But how do I do it with so many different types involved?
Maybe try with this
Map<String, dynamic> convert(Map<String, String> map) {
return {
for (final entry in map.entries)
entry.key: int.tryParse(entry.value) ??
double.tryParse(entry.value) ??
entry.value
};
}
Example:
import 'dart:convert';
void main() {
Map<String, String> map = {
"field1": "1",
"field2": "Two",
"field3": "0.03",
"field40": "four40",
};
final newMap = convert(map);
print(jsonEncode(newMap));
//output: {"field1":1,"field2":"Two","field3":0.03,"field40":"four40"}
}
You could use the map method to go through each element and cast it if necessary.
bool isInt(num value) => (value % 1) == 0;
final Map<String, dynamic> desireddMap = currentMap.map((key, value) {
dynamic newValue = value;
// Check if value is a number
final numVal = num.tryParse(value);
if (numVal != null) {
// If number is a int, cast it to int
if (isInt(numVal)) {
newValue = numVal.toInt();
} else {
// Else cast it to double
newValue = numVal.toDouble();
}
}
return MapEntry(key, newValue);
});

How can i convert a JSON String to List<String> in flutter?

I`m trying to retrieve the content of a table from oracle apex to my flutter app with http.get method, and atribute the values to a class i created. Problem is that 3 of the atributes of this class need to be List, so, when i try to map it, it returns this error: [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] Unhandled Exception: type 'String' is not a subtype of type 'List' in type cast.
this is the JSON:
{
"items": [
{
"id": "1",
"nome": "Feijão Tropeiro",
"id_dia_da_semana": "seg",
"id_categoria": "ga",
"url_da_imagem": "https://live.staticflickr.com/65535/52180505297_2c23a61620_q.jpg",
"ingredientes": "vários nadas"
}
],
and this is the class:
// ignore_for_file: public_member_api_docs, sort_constructors_first
import 'dart:convert';
class Meal {
final String id;
final String descricao;
final List<String> ingredients;
final List<String> idDiaSem;
final List<String> idCategory;
final String imageUrl;
const Meal({
required this.id,
required this.descricao,
required this.ingredients,
required this.idDiaSem,
required this.idCategory,
required this.imageUrl,
});
Map<String, dynamic> toMap() {
return <String, dynamic>{
'id': id,
'nome': descricao,
'ingredientes': ingredients,
'id_dia_da_semana': idDiaSem,
'id_categoria': idCategory,
'url_da_imagem': imageUrl,
};
}
factory Meal.fromMap(Map<String, dynamic> map) {
return Meal(
id: map['id'] as String,
descricao: map['nome'] as String,
ingredients: map['ingredientes'] as List<String>,
idDiaSem: map['id_dia_da_semana'] as List<String>,
idCategory: map['id_categoria'] as List<String>,
imageUrl: map['url_da_imagem'] as String,
);
}
String toJson() => json.encode(toMap());
factory Meal.fromJson(String source) =>
Meal.fromMap(json.decode(source) as Map<String, dynamic>);
}
can anyone help me please to fix this error? i`ve tried to convert it unsuccessfully
When you have a string you want to parse to a list, there should be a separator. For example, let's suppose this strings:
// The separator here is a comma with a space, like ', '
String str1 = 'ingredient1, ingredient2, bread, idunno, etc';
// The separator here is a simple space, ' '
String str2 = 'ingredient1 ingredient2 bread idunno etc';
Once you identified the separator in the string, you may want to use the string split method in dart, specifying the separator. For example:
// Separator is a simple comma with no spaces, ','
String str1 = 'ingredient1,ingredient2,bread,idunno,etc';
// Splits the string into array by the separator
List<String> strList = str1.split(',');
// strList = ['ingredient1', 'ingredient2', 'bread', 'idunno', 'etc'];
More information on the split dart method at https://api.dart.dev/stable/2.14.4/dart-core/String/split.html
EDIT: Example with your code, supposing the property ingredients is a string that represents an array of strings, separated with ",":
factory Meal.fromMap(Map<String, dynamic> map) {
return Meal(
id: map['id'] as String,
descricao: map['nome'] as String,
ingredients: (map['ingredientes'] as String).split(','),
// ...
You can't cast them to List<String> because they simply aren't a list. If you want them to be a List with a single element you could do this instead:
ingredients: [map['ingredientes'] as String],
idDiaSem: [map['id_dia_da_semana'] as String],
idCategory: [map['id_categoria'] as String],
or make sure the JSON has them as list like
{
"items": [
{
"id": "1",
"nome": "Feijão Tropeiro",
"id_dia_da_semana": ["seg"],
"id_categoria": ["ga"],
"url_da_imagem": "https://live.staticflickr.com/65535/52180505297_2c23a61620_q.jpg",
"ingredientes": ["vários nadas"]
}
],
try this:
static List<Meal> fromMap(Map<String, dynamic> map) {
List<Meal> result = [];
for(var item in map['items']){
result.add(Meal(
id: item['id'] as String,
descricao: item['nome'] as String,
ingredients: item['ingredientes'] as String,
idDiaSem: item['id_dia_da_semana'] as String,
idCategory: item['id_categoria'] as String,
imageUrl: item['url_da_imagem'] as String,
))
}
return result;
}

Cast Complex JSON Dart

the dart code below allows you to decode a json that comes from a backend inside resultValue, I have the response of the rest call with the json shown below, when I go to create the list with the values I have the following error, to what is due? how do i fix it?
JSON Link
Error:
//Line: return data.map((jsonObject) => new Manutenzione(
flutter: Errore: type 'List<String>'
is not a subtype of type 'String' in type cast
Dart code:
var urlmod = await Storage.leggi("URL") + "/services/rest/v3/processes/PreventiveMaint/instances";
final resultValue = await apiRequest(Uri.parse(urlmod), {}, UrlRequest.GET, true);
Map<String, dynamic> map = json.decode(resultValue);
List<dynamic> data = map["data"];
try {
return data
.map((jsonObject) => new Manutenzione(
["_id"] as String,
["_user"] as String,
["__user_description"] as String,
["Description"] as String,
["ShortDescr"] as String,
["_Site_description"] as String,
["_Team_description"] as String,
["_status_description"] as String,
["_Company_description"] as String,
))
.toList();
} catch (err) {
print("Errore: " + err.toString());
}
return List.empty();
}
JSON:
{
...
data: [
{
_id: value1,
_user: value2,
..
},
{
_id: value1,
_user: value2,
..
},
]
}
You forgot to specify jsonObject before the square brackets.
var urlmod = await Storage.leggi("URL") + "/services/rest/v3/processes/PreventiveMaint/instances";
final resultValue = await apiRequest(Uri.parse(urlmod), {}, UrlRequest.GET, true);
Map<String, dynamic> map = json.decode(resultValue);
List<dynamic> data = map["data"];
try {
return data
.map((jsonObject) => new Manutenzione(
jsonObject["_id"] as String,
jsonObject["_user"] as String,
jsonObject["__user_description"] as String,
jsonObject["Description"] as String,
jsonObject["ShortDescr"] as String,
jsonObject["_Site_description"] as String,
jsonObject["_Team_description"] as String,
jsonObject["_status_description"] as String,
jsonObject["_Company_description"] as String,
))
.toList();
} catch (err) {
print("Errore: " + err.toString());
}
return List.empty();
}

Hello, I'm trying to figure out how factory constructor working in dart

I've took the code from flutter.dev which use factory for fetching data from the internet.
import 'dart:convert';
Future<Album> fetchAlbum() async {
final response = await http.get('https://jsonplaceholder.typicode.com/albums/1');
if (response.statusCode == 200) {
// If the server did return a 200 OK response,
// then parse the JSON.
return Album.fromJson(jsonDecode(response.body));
} else {
// If the server did not return a 200 OK response,
// then throw an exception.
throw Exception('Failed to load album');
}
}
class Album {
final int userId;
final int id;
final String title;
Album({this.userId, this.id, this.title});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
userId: json['userId'],
id: json['id'],
title: json['title'],
);
}
}
I had tried to repeat it in my code but it didn't work. And I'm confused why it doesn't work because I do the same as in the example.
Future<Album> fetchAlbum() {
Map<String, dynamic> map = {
"photo": "another data",
"id": "dsiid1dsaq",
};
return Album.fromJson(map);
}
class Album {
String photo;
String id;
Album({this.photo, this.id});
factory Album.fromJson(Map<String, dynamic> json) {
return Album(
photo: json['photo'],
id: json['id'],
)`
}
}
It tells me that: "A value of type 'Album' can't be returned from function 'fetchAlbum' because it has a return type of 'Future'."
I hope this may help you.
Future<Album> fetchAlbum() async {
Map<String, dynamic> map = {
"photo": "another data",
"id": "dsiid1dsaq",
};
return Album.fromJson(map);
}
or like this
Album fetchAlbum() {
Map<String, dynamic> map = {
"photo": "another data",
"id": "dsiid1dsaq",
};
return Album.fromJson(map);
}
The problem isn't in the factory constructor itself. The problem is you're declaring your function fetchAlbum to be of type Future<Album> when in reality it returns just a Syncronous Album...
The example from the Flutter Documentation has a return type of Future<T> because it uses the async and await keyword when dealing with network requests so it returns a Future.
Change:
Album fetchAlbum() {
Map<String, dynamic> map = {
"photo": "another data",
"id": "dsiid1dsaq",
};
return Album.fromJson(map);
}

Parse dynamic json element to the same field

I try to convert a json response to a list of persons.
This solution works but maybe there is a better solution to parse it.
(I can't change the response structure, but i can change the person if necessary)
Json Response:
{
"name1": {
"address": "abc",
"city": "xy"
},
"name2": {
"address": "abcdef",
"city": "xyzzzz"
}
}
My Person:
class Person{
name:string;
city:string;
address:string;
constructor(name: string, city: string, address: string) {
this.name = name;
this.city = city;
this.address = address;
}
}
My example implementation:
const value = JSON.parse(data);
const arr:Person[] = [];
for (var key in value) {
if (value.hasOwnProperty(key)) {
arr.push(new Person(key, value[key].city, value[key].address));
}
}
JSON.parse is dangerous, you must do with try catch
let value
try {
value = JSON.parse(data);
} catch (err) {
value = {};
}
const arr:Person[] = Object.keys(value)
.map(key => new Person(key, value[key].city, value[key].address));