I have the following structure that is returned from my API. How do I convert it to a dart object?
[
{
"stateName": "Alabama",
"stateAbbr": "AL"
},
{
"stateName": "Alaska",
"stateAbbr": "AK"
}
]
Basically, I want to display a flutter dropdown box with the stateName value..
It's a list of maps.
first make a State class:
class State{
final String stateName;
final String stateAbbr;
State({
this.stateName,
this.stateAbbr,
}) ;
factory State.fromJson(Map<String, dynamic> json){
return new State(
id: json['stateName'],
title: json['stateAbbr'],
);
}
}
then list of States:
class StatesList {
final List<State> States;
StatesList({
this.States,
});
factory StatesList.fromJson(List<dynamic> parsedJson) {
List<State> States = new List<State>();
States = parsedJson.map((i)=>State.fromJson(i)).toList();
return new StatesList(
States: States,
);
}
}
for more information read this article
class State {
String stateName;
String stateAbbr;
State({this.stateName, this.stateAbbr});
State.fromJson(Map<String, dynamic> json) {
stateName = json['stateName'];
stateAbbr = json['stateAbbr'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['stateName'] = this.stateName;
data['stateAbbr'] = this.stateAbbr;
return data;
}
}
use this website [https://javiercbk.github.io/json_to_dart/][1] it can help you to convert any object JSON to Dart class, and after that, you should use List Object of type State.
Related
Response 1:
{
"status" :"ok",
"message":"found",
"data" : {
"key1" :"value1",
"key2" :"value2"
}
}
Response 2 :
{
"status": "ok",
"message": "found",
"data": {
"users": [
{
"key1": "value1",
"key2": "value2"
}
]
}
}
Want to achieve for creating common class with type T.
it can be parsed like this :
Common<List<Data>> commonRes = Common<List<Data>>.fromJson(jsonDecode(res.body));
or
Common<Data> commonRes = Common<Data>.fromJson(jsonDecode(res.body));
Wanted to achieve same as java generic type T.
Anyone knows how to achieve this in dart ?
Tried to create common class like this. but, no luck.
class Common<T> {
String? status;
String? message;
T? data;
Common({
this.status,
this.message,
this.data,
});
Common.fromJson(Map<String, dynamic> json) {
status = json['status'];
message = json['message'];
data = json['data'] as T;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data1 = Map<String, dynamic>();
data1['status'] = this.status;
data1['message'] = this.message;
data1['data'] = this.data;
return data1;
}
}
It becomes apparent rather quickly that what you were trying to do is impossible, as dart has no idea how to convert json['data'] to T and it can't know, a similar thing is the case in the toJson() function.
Usually the way to solve this is by helping them out and providing generator functions, which some of the code generator libraries also do, which I would suggest checking out. Anyway, here is the general idea behind it if you want to implement it yourself, but I recommend using a codegen library as this gets pretty old rather quickly once you have many API calls etc.
import 'dart:convert';
class Common<T> {
String? status;
String? message;
T? data;
Common({
this.status,
this.message,
this.data,
});
Common.fromJson(Map<String, dynamic> json, T Function(Map<String, dynamic>) fromTJSON) {
status = json['status'];
message = json['message'];
data = fromTJSON(json['data']);
}
Map<String, dynamic> toJson(Map<String, dynamic> Function(T?) toTJSON) {
final Map<String, dynamic> data1 = Map<String, dynamic>();
data1['status'] = status;
data1['message'] = message;
data1['data'] = toTJSON(data);
return data1;
}
}
class ClassA {
String? a;
ClassA({this.a});
ClassA.fromJson(Map<String, dynamic> json) {
a = json['a'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data1 = Map<String, dynamic>();
data1['a'] = a;
return data1;
}
}
class ClassB {
String? b;
ClassB({this.b});
ClassB.fromJson(Map<String, dynamic> json) {
b = json['b'];
}
static ClassB? generatorFoo(Map<String, dynamic> json) {
return null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data1 = Map<String, dynamic>();
data1['b'] = b;
return data1;
}
}
int main() {
String c1JSON = '''
{
"status" :"ok",
"message":"found",
"data" : {
"a" :"someA"
}
}
''';
String c2JSON = '''
{
"status" :"ok",
"message":"found",
"data" : {
"b" :"someb"
}
}
''';
Map<String,dynamic> map1 = jsonDecode(c1JSON);
Common<ClassA> cA = Common.fromJson(map1, (map) => ClassA.fromJson(map));
print(cA.toJson((obj) => obj != null ? obj.toJson() : {}));
Map<String,dynamic> map2 = jsonDecode(c2JSON);
Common<ClassB> cB = Common.fromJson(map2, (map) => ClassB.fromJson(map));
print(cB.toJson((obj) => obj != null ? obj.toJson() : {}));
return 0;
}
In your case you will also need to write a function to help with the mapping of the lists, the general idea is to provide a generator function so you can encode and decode the nested generic types.
So I'm new to flutter and I simply want to display an Object that I receive from a server.
The Object looks something like this. So normally i would do something like Global.mEnergy.value
{
"Global":{
"mEnergy":{
"value":"-0",
"name":"WZ Wärmemenge",
"id":730,
"unit":"kWh",
"type":"value"
},
"mPower":{
"value":"-0.0",
"name":"WZ Leistung",
"id":732,
"unit":"kW",
"type":"value"
},
"xRelease":{
"value":"34",
"name":"Releaseinfo",
"id":727,
"unit":"",
"type":"value"
},
"xVersion":{
"value":"12.00",
"name":"Version Software",
"id":711,
"unit":"",
"type":"value"
},
"name":"Test"
},
"HW1":{
"rState_HW1":{
"value":"10",
"name":"State",
"id":222,
"unit":"",
"type":"value"
},
"pSetTemp_HW1":{
...
},
"rTopTemp_HW1":{
...
},
"pMinTemp_HW1":{
...
},
"pHWChrgTime1Begin_HW1":{
...
}
}
}
But I have really no idea how to start. I know i have to create a class like that
class Device {
final Object hw1;
final Object hw2;
final Object circuit1;
final Object circuit2;
final Object circuit3;
final Object circuit4;
final Object global;
const Device(
{required this.hw1,
required this.hw2,
required this.circuit1,
required this.circuit2,
required this.circuit3,
required this.circuit4,
required this.global});
factory Device.fromJson(Map<String, dynamic> json) {
return Device(
hw1: json['HW1'] as Object,
hw2: json['HW2'] as Object,
circuit1: json['1'] as Object,
circuit2: json['2'] as Object,
circuit3: json['3'] as Object,
circuit4: json['4'] as Object,
global: json['Global'] as Object,
);
}
}
Is there no easy way how I can access the object like this?
Text(snapshot.data!.global.mEnergy.value)
Most often, my strategy is to create classes that mimic the data structure for an API. That gives me the type-safe approach to getting and manipulating the data I need to.
Taking your data set, I have come up with some classes. The first is CommonProperties. Objects such as "mEnergy" in "global" and "rState_HW1" in "HW1" are composed of these properties.
class CommonProperties {
double? value;
String? name;
int? id;
String? unit;
String? type;
CommonProperties({
this.value,
this.name,
this.id,
this.unit,
this.type
});
factory CommonProperties.fromJson(dynamic data) {
data = data ?? {};
return CommonProperties(
value: data["value"],
name: data["name"],
id: data["id"],
unit: data["unit"],
type: data["type"]
);
}
Map<String, dynamic> toJson() {
return {
"value": value,
"name": name,
"id": id,
"unit": unit,
"type": type
};
}
}
Now you have the 2 upper-tier objects called "Global" and "HW1". These are composed of CommonProperties objects.
class Global {
CommonProperties? mEnergy;
CommonProperties? mPower;
CommonProperties? xRelease;
CommonProperties? xVersion;
String? name;
Global({
this.mEnergy,
this.mPower,
this.xRelease,
this.xVersion,
this.name
});
factory Global.fromJson(dynamic data) {
data = data ?? {};
return Global(
mEnergy: CommonProperties.fromJson(data["mEnergy"]),
mPower: CommonProperties.fromJson(data["mPower"]),
xRelease: CommonProperties.fromJson(data["xRelease"]),
xVersion: CommonProperties.fromJson(data["xVersion"]),
name: data["name"]
);
}
Map<String, dynamic> toJson() {
return {
"mEnergy": mEnergy!.toJson(),
"mPower": mPower!.toJson(),
"xRelease": xRelease!.toJson(),
"xVersion": xVersion!.toJson(),
"name": name
};
}
}
class HW1 {
CommonProperties? rState_HW1;
CommonProperties? pSetTemp_HW1;
CommonProperties? pTopTemp_HW1;
CommonProperties? rTopTemp_HW1;
CommonProperties? pMinTemp_HW1;
CommonProperties? pHWChrgTime1Begin_HW1;
HW1({
this.rState_HW1,
this.pSetTemp_HW1,
this.pTopTemp_HW1,
this.rTopTemp_HW1,
this.pMinTemp_HW1,
this.pHWChrgTime1Begin_HW1,
});
factory HW1.fromJson(dynamic data) {
data = data ?? {};
return HW1(
rState_HW1: CommonProperties.fromJson(data["rState_HW1"]),
pSetTemp_HW1: CommonProperties.fromJson(data["pSetTemp_HW1"]),
pTopTemp_HW1: CommonProperties.fromJson(data["pTopTemp_HW1"]),
rTopTemp_HW1: CommonProperties.fromJson(data["rTopTemp_HW1"]),
pMinTemp_HW1: CommonProperties.fromJson(data["pMinTemp_HW1"]),
pHWChrgTime1Begin_HW1: CommonProperties.fromJson(data["pHWChrgTime1Begin_HW1"]),
);
}
Map<String, dynamic> toJson() {
return {
"rState_HW1": rState_HW1!.toJson(),
"pSetTemp_HW1": pSetTemp_HW1!.toJson(),
"pTopTemp_HW1": pTopTemp_HW1!.toJson(),
"rTopTemp_HW1": rTopTemp_HW1!.toJson(),
"pMinTemp_HW1": pMinTemp_HW1!.toJson(),
"pHWChrgTime1Begin_HW1": pHWChrgTime1Begin_HW1!.toJson(),
};
}
}
Finally, I put it all together to build a class that represents the entire DataSet.
class DataSet {
Global? global;
HW1? hw1;
DataSet({
this.global,
this.hw1
});
factory DataSet.fromJson(dynamic data) {
data = data ?? {};
return DataSet(
global: Global.fromJson(data["global"]),
hw1: HW1.fromJson(data["HW1"])
);
}
Map<String, dynamic> toJson() {
return {
"global": global!.toJson(),
"hw1": hw1!.toJson(),
};
}
}
Notice that each class has a constructor for fromJson(data) and a method for toJson(). This is helpful to easily go to and from JSON data for interacting with APIs and such.
Now that I have everthing put together, I can pass the parsed JSON object from an API call into the DataSet.fromJson(data) constructor and I will have a type-safe object to work with all the data within that data set.
var parsedData = json.decode(httpResponse.body);
DataSet dataSet = DataSet.fromJson(parsedData);
print(dataSet.global.mEnergy.value);
print(dataSet.hw1.rState_HW1.value);
I have a Google maps API where in i was trying to save the place key and the JSON response of that particular place in the SQFLite. I was able to write the fromJSON method but how to write the toMap method?
This is the model without the toMap method
class GeometryModel {
final LocationModel locationModel;
GeometryModel({required this.locationModel});
factory GeometryModel.fromJson(Map<dynamic, dynamic> parsedJson) {
return GeometryModel(locationModel: LocationModel.fromJson(parsedJson['location']));
}
}
class LocationModel {
final double latitude;
final double longitude;
LocationModel({required this.latitude, required this.longitude});
factory LocationModel.fromJson(Map<dynamic, dynamic> parsedJson) {
return LocationModel(latitude: parsedJson['lat'], longitude: parsedJson['lng']);
}
}
class PlaceModel {
final String placeId;
final GeometryModel geometryModel;
final String address;
final String name;
PlaceModel({required this.placeId, required this.geometryModel, required this.address, required this.name});
factory PlaceModel.fromJson(Map<String, dynamic> parsedJson) {
return PlaceModel(
placeId: parsedJson['place_id'],
name: parsedJson['vicinity'],
geometryModel: GeometryModel.fromJson(parsedJson['geometry']),
address: parsedJson['formatted_address'],
);
}
}
This is the response I'm receiving from the server
{
"html_attributions": [],
"result": {
"formatted_address": "New York, NY, USA",
"geometry": {
"location": {
"lat": 40.7127753,
"lng": -74.0059728
},
"viewport": {
"northeast": {
"lat": 40.91757705070789,
"lng": -73.70027206817629
},
"southwest": {
"lat": 40.47739906045452,
"lng": -74.25908991427882
}
}
},
"icon_background_color": "#7B9EB0",
"icon_mask_base_uri": "https://maps.gstatic.com/mapfiles/place_api/icons/v2/generic_pinlet",
"name": "New York"
"url": "https://maps.google.com/?q=New+York,+NY,+USA&ftid=0x89c24fa5d33f083b:0xc80b8f06e177fe62",
"utc_offset": -240,
"vicinity": "New York","
},
"status": "OK"
}
Use JsonToDart website. You just need to paste your JSON data and it will convert json data to model class along with fromJson() and toJson() or toMap().
NOTE: If you get json syntax error you need to verify your json data is Valid or not. For json validation check json_parser_online website.
There's another option to work with JSON data and without creating models and without using generators! How? Using the g-json package.
See my answer to another question (How to parse complex JSON using default methods in Flutter?) that can help you, Naan Avan.
Here is the example of Viewport, how to convert toJson/toMap and use this link to help you to convert your JSON to map
class Viewport {
Viewport viewport;
Viewport({this.viewport});
Viewport.fromJson(Map<String, dynamic> json) {
viewport = json['viewport'] != null
? new Viewport.fromJson(json['viewport'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.viewport != null) {
data['viewport'] = this.viewport.toJson();
}
return data;
}
}
class Viewport {
Northeast northeast;
Northeast southwest;
Viewport({this.northeast, this.southwest});
Viewport.fromJson(Map<String, dynamic> json) {
northeast = json['northeast'] != null
? new Northeast.fromJson(json['northeast'])
: null;
southwest = json['southwest'] != null
? new Northeast.fromJson(json['southwest'])
: null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.northeast != null) {
data['northeast'] = this.northeast.toJson();
}
if (this.southwest != null) {
data['southwest'] = this.southwest.toJson();
}
return data;
}
}
class Northeast {
double lat;
double lng;
Northeast({this.lat, this.lng});
Northeast.fromJson(Map<String, dynamic> json) {
lat = json['lat'];
lng = json['lng'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['lat'] = this.lat;
data['lng'] = this.lng;
return data;
}
}
You can achieve it like this :
Map<String, dynamic> toMap() {
var map = Map<String, dynamic>();
map['place_id'] = placeId;
map['address'] = address;
map['name'] = name;
map['geometry_model_id']=geometryModel.id; //saves id
return map;}
In my Flutter app I receive notifications with a custom payload, like:
{ notification:
{
title: Test,
body: AAAA
},
data:
{
productId: Axe,
page: Products,
click_action: FLUTTER_NOTIFICATION_CLICK
}
}
Everything works well. I also can handle the payload of the notification by access it through:
message['data']['page']
But I rather would like to use an Interface/Class to name the data by key, for example:
message.data.page and message.data.productId
So I tried:
class NotificationMessage {
Map notification;
Map data;
NotificationMessage(this.notification, this.data);
}
...
NotificationMessage _message = message; // Assigning the payload to the final
...
This where I get stuck: here I got the error: A value of type 'Map<dynamic, dynamic>' can't be assigned to a variable of type 'NotificationMessage'.
My class isn't finished yet, but how to continue?
I' aware of json_serializable, but before any tooling, I would like to understand it fully.
First, you need to build the two models for notification and data as follows
class DataMessage {
final String productId;
final String page;
final String click_action;
DataMessage(this.productId, this.page, this.click_action);
factory DataMessage.fromJson(Map<dynamic, dynamic> json) {
return DataMessage(
json['productId'] as String,
json['page'] as String,
json['click_action'] as String,
);
}
}
class NotificationMessage {
final String title;
final String body;
NotificationMessage(this.title, this.body);
factory NotificationMessage.fromJson(Map<dynamic, dynamic> json) {
return NotificationMessage(
json['title'] as String,
json['body'] as String,
);
}
}
The factory method convert map types into model classes.
Then you have to build a model for the response message as follows
class Message {
final NotificationMessage notification;
final DataMessage data;
Message(this.notification, this.data);
factory Message.fromJson(Map<dynamic, dynamic> json) {
final Map<dynamic, dynamic> mapNotification = json['notification'];
final Map<dynamic, dynamic> mapData = json['data'];
final dataModel = DataMessage.fromJson(mapData);
final notificationModel = NotificationMessage.fromJson(mapNotification);
return Message(
notificationModel as NotificationMessage,
dataModel as DataMessage,
);
}
}
Note that the factory method allows you to convert the maps for each model to a class model
So you can define your response as a class
Map<dynamic, dynamic> messageResponse = {
'notification': {'title': 'Test', 'body': 'AAAA'},
'data': {
'productId': 'Axe',
'page': 'Products',
'click_action': 'FLUTTER_NOTIFICATION_CLICK'
}
};
final Message message = Message.fromJson(messageResponse);
print(message.data.productId);
print(message.data.page);
print(message.data.click_action);
print(message.notification.title);
print(message.notification.body);
Hope that can help you
Instance of the json object. this way you can use a map for any instance without modifying the class
{ "notification":
{
"title": "Test",
"body": "AAAA"
},
"data":
{
"productId": "Axe",
"page": "Products",
"click_action": "FLUTTER_NOTIFICATION_CLICK"
}
}
Class looks like;
class NotificationMessage {
NotificationMessage({
this.notification,
this.data,
});
final Notification notification;
final Data data;
factory NotificationMessage.fromJson(Map<String, dynamic> json) => NotificationMessage(
notification: Notification.fromJson(json["notification"]),
data: Data.fromJson(json["data"]),
);
Map<String, dynamic> toJson() => {
"notification": notification.toJson(),
"data": data.toJson(),
};
}
class Data {
Data({
this.productId,
this.page,
this.clickAction,
});
final String productId;
final String page;
final String clickAction;
factory Data.fromJson(Map<String, dynamic> json) => Data(
productId: json["productId"],
page: json["page"],
clickAction: json["click_action"],
);
Map<String, dynamic> toJson() => {
"productId": productId,
"page": page,
"click_action": clickAction,
};
}
class Notification {
Notification({
this.title,
this.body,
});
final String title;
final String body;
factory Notification.fromJson(Map<String, dynamic> json) => Notification(
title: json["title"],
body: json["body"],
);
Map<String, dynamic> toJson() => {
"title": title,
"body": body,
};
}
A function to build as
Future<NotificationMessage> getNotf() {
var parsedJson = json.decode(//your received object);
return NotificationMessage.fromJson(parsedJson);
}
Now you can receive this in a builder such as
_futureNotifications =Future<NotificationMessage>
_futureNotifications = getNotf(); //this is a function and can be used after a gesture or initState
FutureBuilder<NotificationMessage>(
future: _futureNotifications,
builder: (context, snapshot) {
}
I'm new to flutter and despite my research I can't find the answers. How to update the values of a class according to a dynamic variable.
For example in my User class I want to update the salary of my User according to a map. How to call the key to update the class ?
My class :
class Users{
List<User> user;
Users({this.user});
Users.fromJson(Map<String, dynamic> json) {
if (json['user'] != null) {
user= new List<User>();
json['user'].forEach((v) {
user.add(new User.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.user!= null) {
data['user'] = this.user.map((v) => v.toJson()).toList();
}
return data;
}
#override
String toString() {
return '{${this.user}}';
}
}
class User{
String name;
int gender;
num salary;
User(
{this.name,
this.gender,
this.salary,
});
User.fromJson(Map<String, dynamic> json) {
name= json['name'];
gender= json['gender'];
salary= json['salary'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
data['gender'] = this.gender;
data['salary'] = this.salary;
return data;
}
#override
String toString() {
return '{ '
'${this.name},'
'${this.gender},'
'${this.salary},'
'}';
}
}
Here the function that calculate the new salary of my User and update this.
func_OrderedUsers(List<User> users)
{
List<User> _UsersInOrder;
if (users.length > 0)
{
users.forEach((user)
{
Map _params = {
"salary" : func_CalculateNewSalary(user)
};
func_UpdateItem(user, _params);
});
//... some code
}
And My function UpdateItem :
func_UpdateItem(var item, Map params)
{
if(params != null){
params.forEach((key, value)
{
if(value != null){
// Here is my problem !
// How to use the key variable ?
item.salary = value; // If I write directly the parameter it works (salary)
}
});
}
return item;
}
What you're trying to do is something that dart:mirrors would do. However, since you seem to be using flutter, this is not available for you to use.
Instead you'll have to manually map each key of your Map to a field in your object, just like in your fromJson constructor. You could add a method that does this within your class. Ex.
void updateFieldsFromMap(Map<String, dynamic> input) {
if(input['name'] != null) name = input['name'];
if(input['gender'] != null) gender = input['gender'];
if(input['salary'] != null) salary = input['salary'];
}
You can try to use factory
factory User.fromJson(Map<String, dynamic> json) {
return new User(
name: data['name'],
gender: data['gender'],
salary: data['salary'],
);
}