Flutter display Object entries - flutter

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);

Related

Convert class object to data value flutter dart

This is my JSON:
{
'malls' : [{'id':1 , 'name': 'salam'},{'id':2 , 'name': 'salam2'}]
}
And this is my modeling JSON classes:
class MALL {
final int id;
final String name;
MALL({required this.id, required this.name});
factory MALL.fromJson(Map<String, dynamic> data) {
return MALL(id: data['id'], name: data['name']);
}
}
class City {
final List<MALL> malls;
City({required this.malls});
factory City.fromJson(Map<String, dynamic> data) {
var list = data['malls'] as List;
List<MALL> mallList = list.map((i) => MALL.fromJson(i)).toList();
return City(malls: mallList);
}
}
This is my get method:
Future<List<MALL>> get() async {
var response = await http.get(Uri.parse(URL), headers: {"authorization": "Bearer ${token}", "Content-Type": "application/json"});
var data = jsonDecode(response.body);
City api = City.fromJson(data);
return data['malls'];
}
I get this output:
[Instance of 'MALL', Instance of 'MALL']
I want my JSON in output by I got the instance of my classes.
How can I convert the instances to my data? It means I want to return my JSON in output and I can access the keys of malls in my FutureBuilder.
If you wanna print the response of a Class you can override the toString method to print the response of the Class. Example:
class MALL {
final int id;
final String name;
MALL({required this.id, required this.name});
factory MALL.fromJson(Map<String, dynamic> data) {
return MALL(id: data['id'], name: data['name']);
}
#override
String toString() => "{ id : $id, name : $name}";
}
Now you will see the result in console.
Inside your FutureBuilder yo will get list of Malls. Thats you have to use loop or list view builder to access those elemet.
if you want to print the list data. you have to print first element
inside your future build when data is loded.
print(data.first.toString())
add this line of code inside your malls calss
#override
String toString() => "{ id : $id, name : $name}";

How to do a toJson encode method on Dart/Flutter?

I used the fromJson method to recover a Struct with a List from Json decode http request and receiver it on my class, but now i want to do a reverse, i want to pass the data on my class to my toJson method and send him to a Json encode http POST. Please, i new on Dart/Flutter, someone know how to do this?
import 'dart:convert';
List<Itens> userFromJson(String str) =>
List<Itens>.from(jsonDecode(str).map((x) => Itens.fromJson(x)));
class Coletas {
final int codigo;
final String dataIni;
late String? dataFin;
late String? status;
final List<Itens> itemList;
Coletas(
{
required this.dataIni,
this.dataFin,
this.status,
required this.codigo,
required this.itemList
}
);
factory Coletas.fromJson(Map<String, dynamic> json) {
return Coletas(
dataIni: json['dtData'],
codigo: json['iCodigo'],
itemList: List<Itens>.from(json['stItens'].map((x) => Itens.fromJson(x))),
);
}
Map<String, dynamic> toMap() {
return {
'codigo': codigo,
'dataIni': dataIni,
'dataFin': dataFin,
'status': status
};
}
}
class Itens {
final int? id;
final int codigo;
late int quantidade;
late String? status;
final String codigoEAN;
Itens({
this.id,
this.status,
required this.codigo,
required this.codigoEAN,
required this.quantidade,
});
Map<String, dynamic> toJson(){
return {
'icodigo' : codigo,
'sCodigoBarras': codigoEAN,
'iQtd': quantidade
};
}
factory Itens.fromJson(Map<String, dynamic> json) {
return Itens(
codigo: json['iCodigo'],
codigoEAN: json['sCodigoBarras'],
quantidade: json['iQtd'],
);
}
Map<String, dynamic> toMap() {
return {
'id': id,
'status': status,
'codigo': codigo,
'codigoEAN': codigoEAN,
'quantidade': quantidade,
};
}
}
I tried to pass ever item on List separeted so, but not happen i expected.
Map<String, dynamic> toJSon(Coletas value) =>
{
'dtData' : dataIni,
'iCodigo': codigo,
'stItens': [],
};
For a better structure - format and use you can look at the flutter serialization documentation : https://docs.flutter.dev/development/data-and-backend/json.
It explains how to create your model and how to generate them to create fromJson and toJson Model based on the defined data. (https://docs.flutter.dev/development/data-and-backend/json#creating-model-classes-the-json_serializable-way)
It will helps you with your parsing - sending - receiving data.
I think you should assign Coletas as
Map<String, dynamic> toJSon(Coletas value) =>
{
'dtData' : value.dataIni,
'iCodigo': value.codigo,
'stItens': value.itemList,
};

How to use polymorphism in dart

Hi I need to use polymorphism in flutter to use it in get data from Restfull API
but it doesn't work.
first I have a base class (Model)
class Model
{
Model();
Model.fromJson(Map<String, dynamic> json) ;
Map<String, dynamic> toJson(){}
}
then I have derived class (City)
class City extends Model {
int id;
String name;
List<Region> regions;
City({this.id, this.name, this.regions});
City.fromJson(Map<String, dynamic> json) {
id = json['id'];
name = json['name'];
if (json['regions'] != null) {
regions = new List<Region>();
json['regions'].forEach((v) {
regions.add(new Region.fromJson(v));
});
}
}
}
and this is a function with getAllModel method
class Repository
{
static Future<List<T>> getAllModel<T extends Model>( apis url) async {
try {
bool tk = await Cache.tokenExists();
if (tk) {
String token = await Cache.getString(keys.api_token);
var body = {};
List<dynamic> data = await Request.callAPI(
apiName.name(url),
body,
method: 'GET', apiToken: token);
List<T> objs = new List();
if (data != null) if (data.length > 0) {
data.forEach((v) {
T r = Model.fromJson(v) as T;
objs.add(r);
});
return objs;
}
return objs;
}
return new List();
} catch (e, stacktrace) {
print("getAll() | catch exception");
print(e);
print(stacktrace);
return new List();
}
}
}
finally this is a call method
static Future<List<City>> getCities() async {
return Repository.getAllModel(apis.getCities);
}
this is a problem
type 'Model' is not a subtype of type 'City' in type cast
How can I solve this ?
Model.fromJson(v) will always return a value of the base type, Model.
You can't cast this to T = City here:
T r = Model.fromJson(v) as T;
because Dart can't know how to turn a Model into a City.
You would want to call “T.fromJson(v)”, so to speak, but Dart doesn't allow us to speak polymorphically about constructors.
I think your best bet might be to pass the relevant fromJson function along to getAllModel:
// The type of functions that take a JSON map and return T.
typedef JsonDecoder<T> = T Function(Map<String, dynamic> json);
// Use a provided `fromJson` callback to transform your API results:
Future<List<T>> getAllModel<T extends Model>(String url,
JsonDecoder<T> fromJson) async {
...
T r = fromJson(v);
...
}
// And provide it like so:
void myFunction() {
final cities = await getAllModel<City>("city url", (j) => City.fromJson(j));
}
(Somewhat annoyingly, we can't even write this:)
getAllModel<City>("city url", City.fromJson);
^^^^^^^^^^^^^
By the way, I recommend looking into json_serializable.
Here is an aproach i am thinking of taking to render different components returned from a REST api (strapi)
I want to render the components based on type from a response like this
{
"data": {
"id": 1,
"homepage": [
{
"id": 1,
"__component": "explore.search",
"enabled": true,
"include_articles": true,
"include_menu_entries": true,
"include_contributors": true
},
{
"id": 1,
"__component": "explore.whats-new",
"entry_count": 7
}
]
},
"meta": {}
}
I created a base component model like this to capture the common parameters to be extended by each component model later
class CmsComponent {
CmsComponent({
required this.id,
required this.component,
});
int id;
String component;
factory CmsComponent.fromJson(Map<String, dynamic> json) => CmsComponent(
id: json["id"],
component: json["__component"],
);
Map<String, dynamic> toJson() => {
"id": id,
"__component": component,
};
}
then an example of a single component model is
class CmsComponentSearch extends CmsComponent{
CmsComponentSearch({
required id,
required component,
required this.enabled,
required this.includeArticles,
required this.includeMenuEntries,
required this.includeContributors,
}) : super(id: id, component: component);
bool enabled;
bool includeArticles;
bool includeMenuEntries;
bool includeContributors;
factory CmsComponentSearch.fromJson(Map<String, dynamic> json) => CmsComponentSearch(
id: json["id"],
component: json["__component"],
enabled: json["enabled"],
includeArticles: json["include_articles"],
includeMenuEntries: json["include_menu_entries"],
includeContributors: json["include_contributors"],
);
Map<String, dynamic> toJson() => {
"id": id,
"__component": component,
"enabled": enabled,
"include_articles": includeArticles,
"include_menu_entries": includeMenuEntries,
"include_contributors": includeContributors,
};
}
then at the top level i can create this model with a method to switch out each components model as needed
class CmsExploreHome {
CmsExploreHome({
required this.id,
required this.components,
});
int id;
List<dynamic> components;
factory CmsExploreHome.fromJson(Map<String, dynamic> json) => CmsExploreHome(
id: json["id"],
components: List<dynamic>.from(json["homepage"].map((x) => getCmsComponentModelFromJson(x))),
);
Map<String, dynamic> toJson() => {
"id": id,
"homepage": List<dynamic>.from(components.map((x) => x.toJson())),
};
}
getCmsComponentModelFromJson(Map<String, dynamic> json) {
switch(json['__component']) {
case 'explore.search' : return CmsComponentSearch.fromJson(json);
case 'explore.whats-new' : return CmsComponentWhatsNew.fromJson(json);
default : return CmsComponent.fromJson(json);
}
}
Thats the data modelling done, then in the UI widget i can do something like this
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('explore'),
for (var component in exploreProvider.cmsExploreHome!.components) _RenderComponent(component),
],
),
and add the following widgets
class _RenderComponent extends StatelessWidget {
const _RenderComponent(this.component, {Key? key}) : super(key: key);
final CmsComponent component;
#override
Widget build(BuildContext context) {
if(component is CmsComponentSearch) return CmsSearchComponent(component as CmsComponentSearch);
return Text("${component.component} not implemented");
}
}
and for example
class CmsSearchComponent extends StatelessWidget {
const CmsSearchComponent(this.component, {Key? key}) : super(key: key);
final CmsComponentSearch component;
#override
Widget build(BuildContext context) {
return Text("Search field");
}
}
That gets the job done, the flutter app can receive dynamic types from the REST api in a list and render them

How create a interface (class) in Dart for an nested 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) {
}

How to convert an array to a dart object

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.