flutter assign list values to a class - flutter

Looking for help for assigning List values to a class. Here is my class.
class Specialties {
int id;
String name;
String details;
const Specialties(this.id, this.name, this.details);
}
I have a List created from JSON and I have confirmed it has values, but can not get the values assigned to instantiate the class. I know the class works as when I hardcode values it gets created just fine.
This is how I am trying to do it and can not find why it does not work.
Specialties getSpec(int index) {
return new Specialties(mylist[index].id, mylist[index].name, mylist[index].details);
}
I am sure I am missing something easy, but once I saw hardcoded values working, can not figure it out.
Any help would be great.

It seems like you may be coming from a JavaScript background where object.property
object['property'] are equivalent. In Dart, they are not.
If you parsed a JSON object it will turn into a Dart Map with String keys. Modify your getSpec function to use operator[] instead of dot syntax to read the entries of the Map.
Specialties getSpec(int index) {
return new Specialties(mylist[index]['id'], mylist[index]['name'], mylist[index]['details']);
}
You may want to consider giving Specialties an additional fromMap constructor rather than constructing it in an external function. You should also make the fields of Specialties be final since its constructor is const.
class Specialties {
final int id;
final String name;
final String details;
const Specialties(this.id, this.name, this.details);
factory Specialties.fromMap(Map data) => new Specialties(data['id'], data['name'], data['details']);
}
Then you can say
new Specialties.fromMap(mylist[index])
Finally, there are some other JSON deserialization libraries that you might want to consider to reduce the amount of boilerplate deserialization code: Jaguar, built_value.

If you have a JSON string in the form of '[{"id": 1, "name": "ab", "details": "blabla"},{...}]' you can convert it like this:
List<Specialties> specialties(String jsonstring) {
List parsedList = JSON.decode(jsonstring);
return parsedList.map((i) => new Specialties(
i["id"], i["name"], i["details"]));
}
You will have to import dart:convert to get the method JSON.decode

Related

How to use a factory constructor with null safety

I'm trying to figure out if my updated code is the correct way to use a factory constructor with null safety. I reviewed stackoverflow and the Dart.dev language tour to try to better understand factory constructors. I have struggled to apply the concepts outlined to my code. I'm new to Flutter, Dart and coding. This is my first attempt at using a factory constructor so the primary issue is my lack of understanding and not any issues with the answers on stackoverflow or elsewhere.
After reading a lot I settled on the approach in the code below marked as Updated. The errors are now all gone and my app is behaving as I want but my fear is throwing an error instead of returning null may not be a sound approach. My approach just looks wrong to my beginner eyes. My goal is for my code to work and to also understand why I am using whatever approach I am using so that I can apply that knowledge to future situations. I can provide any additional code that may be needed to comment. Thanks in advance for the help.
Original Code that throws an error
class Job {
Job({required this.name, required this.ratePerHour});
factory Job.fromMap(Map<String, dynamic>? data) {
if (data == null) {
return null;
}
final String name = data['name'];
final int ratePerHour = data['ratePerHour'];
return Job(name: name, ratePerHour: ratePerHour);
}
final String name;
final int ratePerHour;
Map<String, dynamic> toMap() {
return {
'name': name,
'ratePerHour': ratePerHour,
};
}
}
Updated code that works
class Job {
Job({required this.name, required this.ratePerHour});
factory Job.fromMap(Map<String, dynamic>? data) {
if (data != null) {
final String name = data['name'];
final int ratePerHour = data['ratePerHour'];
return Job(name: name, ratePerHour: ratePerHour);
} else {
throw ArgumentError('Data is null');
}
}
final String name;
final int ratePerHour;
Map<String, dynamic> toMap() {
return {
'name': name,
'ratePerHour': ratePerHour,
};
}
}
Your own solution works fine however, I would check data before calling the factory.
factory Job.fromMap(Map<String, dynamic> data) {
return Job(name: data['name'], ratePerHour: data['ratePerHour']);
}
But then again why not use data and call the regular constructor?
Job? job;
if (data != null) {
job = Job(name: data['name'], ratePerHour: data['ratePerHour'])
}
https://dart.dev/guides/language/language-tour#factory-constructors
Factory constructors
Use the factory keyword when implementing a
constructor that doesn’t always create a new instance of its class.
For example, a factory constructor might return an instance from a
cache, or it might return an instance of a subtype. Another use case
for factory constructors is initializing a final variable using logic
that can’t be handled in the initializer list.
You've pointed out several true and good facts, and I feel like that you're on the right way to implement this.
I also feel like there's no straight "right" answer to this question; I think this also connects to concepts as clean code and clean architecture, which are broader than Dart and Flutter themselves
You can either:
Throw and let the caller (upper layer) handle that problem;
Print some logs and return a zero-value to the caller (in your case, an "empty" object).
Case 1 is desirable if you don't want to handle cases like that one.
Case 2 is desirable if you can afford to return something weird like a Job("job name",0) and still be good.
It really depends on what you're building. By looking at your context, I'd probably go with option 1 and try/catch that in a middle layer (maybe you want to show your user "An error occured" whenever data is null)?
Nonetheless, you might need to refactor this feature in a way that allows you not to encounter these edge cases. There's a good chance dependency inversion is your friend, here.

Why "A value of type 'Set<ShProblemHive>' can't be returned from the method 'toHive' because it has a return type of 'ShProblemHive'."

I am trying to connect a Hive database with domain and a data layer. However, I am struggling to transform my entity data class to a HiveObject. With my current approach I receive the error as seen in the title of this post. Other attempts also failed and I start recognizing, I appear to have a lack of understanding, how those constructors work...
So in general, I want to use a class ShProblem in the domain layer that has a constructor
static ShProblem fromEntity(ShmProblemEntity entity) {
return ShProblem(
id: entity.id,
level: entity.level,
);
}
This constructor shall receive/provide data from/to the data source via an entity class. Getting data from Hive should work (not tested, but at least no compile error), however, the other way around does not work as with JSON maps (seen in the toDocument constructor), what I used previously with other databases.
class ShmProblemEntity {
ShmProblemEntity({required this.id, required this.level, });
final int id;
final int level;
static ShmProblemEntity fromHive(ShProblemHive hiveObject) {
return ShmProblemEntity(
id: hiveObject.id,
level: hiveObject.level,
);
}
static ShProblemHive toHive() => {
ShProblemHive(
id: this.id,
level: level,
)
};
Map<String, dynamic> toDocument() => {
"id": id,
"level": level,
};
So, it is strange to me that fromHive throws no error while toHive does, though I notice the difference that fromHive has the same datatype as the class of the constructor while toHive has not.

auto converting json to object in dart flutter

I search google and stackoverflow but did not find some auto converting lib like in C#
I need something in dart-flutter alternative to this code in C#
string jsonTokenData = "{my token json data}";
TokenModel getTokenModel = Newtonsoft.Json.JsonConvert.DeserializeObject<GetTokenModel>(jsonTokenData);
Update
I read the Documentation and I know how to map models with json
this question to who know how Newtonsoft lib work on C#
if you do not know Newtonsoft: the Idea is to convert json data to a model automatically without writing map for each model. Also I know there is a tool to create that map with json for each model automatically but still make code ridiculous.
Update2: as I get a suggestion from community for a similar question that not answer my question. so this is a another explanation:
I have a lot of models these models are updated by time as clients requested or adding new features to some models.
so when an update happen I just need to add the extra properties that has been added to these models, I do not need to warry every time about mapping, spell mistaken or using some tools again to regenerate these codes.
so I'm asking for a function that take two parameters
first one is the type of the model
second one the json string that hold the data
[then in return is an object instance of the passed type]
for simple example if I have this class:
class Car {
String name;
String type;
}
Then I could keep it clean this way without getting it dart with other methods:
Car({
this.name,
this.type,
});
factory Car.fromJson(Map<String, dynamic> json) => Car(
name: json["name"],
type: json["type"],
);
Map<String, dynamic> toJson() => {
"name": name,
"type": type,
};
by the way lib in C# is also take care about arrays, lists and nested classes
I hope this time it explained well
I've added a new Dart package to Jsonize custom classes within any data structure.
This is how your Car example would look like:
import 'package:jsonize/jsonize.dart';
class Car implements Jsonizable<Car> {
final String name;
final String type;
Car({required this.name, required this.type});
// Jsonizable implementation
factory Car.empty() => Car(name: "", type: "");
#override
String get jsonClassCode => "car";
#override
Map<String, dynamic> toJson() => {"name": name, "type": type};
#override
Car? fromJson(value) => Car(name: value["name"], type: value["type"]);
}
void main() {
// Register classes
Jsonize.registerClass(Car.empty());
// Now you can jsonize it wherever
Map<String, dynamic> myMap = {
"my_car": Car(name: "Jessie", type: "Tesla"),
"purchase_dt": DateTime.now(),
};
var jsonRep = Jsonize.toJson(myMap);
var hereIsMyMap = Jsonize.fromJson(jsonRep);
print(hereIsMyMap);
List<dynamic> myList = [
Car(name: "Jessie", type: "Tesla"),
Car(name: "Bob", type: "Ford"),
];
jsonRep = Jsonize.toJson(myList);
var hereIsMyList = Jsonize.fromJson(jsonRep);
print(hereIsMyList);
}
just import dart:convert library like this :
import 'dart:convert';
Then use this code :
json.decode(json)
Take a look at this link : dart:convert library
Doing some research would allow you to not ask here on SO.
JSON decoding is well documented on the flutter site. It points to using the jsonDecode function, which parses the String and returns the resulting JSON object.
String jsonTokenData = "{my token json data}";
dynamic json = jsonDecode(jsonTokenData);
You can pass the decoded object to a custom constructor of your object like .fromJson, which accepts a Map/List depending on your JSON data.
If for some reason creating a constructor to accept JSON data would be too much work/typing or if you're having trouble doing it yourself, you can use a JSON to Dart service like this.

How to make and relate complex table with each other in sqfllite flutter?

I am using sqflite package to store data offline as well once it got from API. I had seen a couple of examples and all used the simple Strings and not lists in their models as a type and due to that I am feeling difficulty in the conversion of these classes in respective tables and link them so that data can be fetch easily once synced. Can someone guide me on how to make create and link tables in sqflite with these types of classes so that they work perfectly?
TodayDeliveriesModel class
class TodayDeliveriesModel {
final String Name;
final List<ItemsModel> allItems;
final bool pending;
TodayDeliveriesModel({this.Name, this.allItems, this.pending});
}
Items Model class:
class ItemsModel {
String name;
String quantity;
ItemsModel({this.name, this.quantity});
}
fetch and Parse JSON data from the server.
Create Database Table with just 3 parameters.
class DeliveryModel{
String name;
String items;
bool isPending;
}
then when you save data in the database, just covert List to String
and save this string as the items.
After then when you get this string from database convert this into again List

Flutter / Inject.dart - Is it possible to simplify or generate code for a 'provided' class instantiation?

Been doing some research on Flutter Dependency Injection,and I kinda settled on Inject.dart
However, I am having some trouble using inject.
Is there any way to simplify instantitation of a injected class?
I have this MyClass, which I need to instantiate passing a HomeStore, however, how can I instatiate it without calling global acessors? (such as the ones made on the Injector file).
It seems I could just use the Get_It package otherwise, which would get me the same results, and without code generation, but I don't quite like the whole global access thing.
My sample:
// current code
class MyClass(){
store = HomeStore(AppInjector().globalHudStore, AppInjector().globalErrorStore);
}
// desired code
class MyClass(){
#instance ?
store = HomeStore();
store = HomeStore.instanciate?();
}
class HomeStore {
#provide
HomeStore(this._globalHudStore, this._globalErrorStore);
final GlobalHudStore _globalHudStore;
final ErrorStore _globalErrorStore;
}
If you are willing to work with json, you might want to consider this package json_serializable. Just search for it at pub.dev.
I can give a little example. Let's say you have a User class/model.
part 'user.g.dart';
#JsonSerializable()
class User {
int id;
#JsonKey(name: 'user_type_id')
int userTypeId;
String email;
#JsonKey(name: 'user_detail')
UserDetail userDetail;
#JsonKey(name: 'user_type')
UserType userType;
#JsonKey(name: 'user_location')
UserLocation userLocation;
User();
factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
Map<String, dynamic> toJson() => _$UserToJson(this);
}
and you fetched a User data via API, and want to create a User variable and fill it with data without having to do that manually.
You can actually do that with just this line of code
User user = User.fromJson(jsonUser);
These even automatically json serializes classes in your User class, as long as those classes are also json serializable, which is defined with #JsonSerializable()
So even with just that single line of code, if the jsonUser which came from the API also has values for UserDetail, UserType, and UserLocation, you can also access them.