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'],
);
}
Related
I am kind of new to flutter and working on the application where I need to save data locally to use it later when user will be offline.
I have a modal class with multiple inner classes:
Modal Class:
import 'package:hive/hive.dart';
part 'DownloadResponse.g.dart';
#HiveType(typeId: 1)
class DownloadResponse extends HiveObject {
#HiveField(0)
UserInfo userInfo;
#HiveField(1)
AppSetting appSetting;
#HiveField(2)
List<Seals> seals;
#HiveField(3)
String success;
#HiveField(4)
String message;
DownloadResponse(
{this.userInfo, this.appSetting, this.seals, this.success, this.message});
DownloadResponse.fromJson(Map<String, dynamic> json) {
userInfo = json['userInfo'] != null
? new UserInfo.fromJson(json['userInfo'])
: null;
appSetting = json['appSetting'] != null
? new AppSetting.fromJson(json['appSetting'])
: null;
if (json['seals'] != null) {
seals = new List<Seals>();
json['seals'].forEach((v) {
seals.add(new Seals.fromJson(v));
});
}
success = json['success'];
message = json['message'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
if (this.userInfo != null) {
data['userInfo'] = this.userInfo.toJson();
}
if (this.appSetting != null) {
data['appSetting'] = this.appSetting.toJson();
}
if (this.seals != null) {
data['seals'] = this.seals.map((v) => v.toJson()).toList();
}
data['success'] = this.success;
data['message'] = this.message;
return data;
}
}
#HiveType(typeId: 2)
class UserInfo extends HiveObject {
String fullName;
String mobileLastSyncDate;
UserInfo({this.fullName, this.mobileLastSyncDate});
UserInfo.fromJson(Map<String, dynamic> json) {
fullName = json['full_name'];
mobileLastSyncDate = json['mobile_last_sync_date'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['full_name'] = this.fullName;
data['mobile_last_sync_date'] = this.mobileLastSyncDate;
return data;
}
}
#HiveType(typeId: 3)
class AppSetting extends HiveObject {
String appWebviewHeight;
String appScreenHeaderSealScan;
String appScreenHeaderSealInfo;
String appScreenHeaderPicture1;
String appScreenHeaderPicture2;
AppSetting(
{this.appWebviewHeight,
this.appScreenHeaderSealScan,
this.appScreenHeaderSealInfo,
this.appScreenHeaderPicture1,
this.appScreenHeaderPicture2});
AppSetting.fromJson(Map<String, dynamic> json) {
appWebviewHeight = json['app_webview_height'];
appScreenHeaderSealScan = json['app_screen_header_seal_scan'];
appScreenHeaderSealInfo = json['app_screen_header_seal_info'];
appScreenHeaderPicture1 = json['app_screen_header_picture_1'];
appScreenHeaderPicture2 = json['app_screen_header_picture_2'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['app_webview_height'] = this.appWebviewHeight;
data['app_screen_header_seal_scan'] = this.appScreenHeaderSealScan;
data['app_screen_header_seal_info'] = this.appScreenHeaderSealInfo;
data['app_screen_header_picture_1'] = this.appScreenHeaderPicture1;
data['app_screen_header_picture_2'] = this.appScreenHeaderPicture2;
return data;
}
}
#HiveType(typeId: 4)
class Seals extends HiveObject {
String sealId;
String sealHtml;
List<Documents> documents;
Seals({this.sealId, this.sealHtml, this.documents});
Seals.fromJson(Map<String, dynamic> json) {
sealId = json['seal_id'];
sealHtml = json['seal_html'];
if (json['documents'] != null) {
documents = new List<Documents>();
json['documents'].forEach((v) {
documents.add(new Documents.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['seal_id'] = this.sealId;
data['seal_html'] = this.sealHtml;
if (this.documents != null) {
data['documents'] = this.documents.map((v) => v.toJson()).toList();
}
return data;
}
}
#HiveType(typeId: 5)
class Documents extends HiveObject {
String documentId;
String documentName;
String documentLink;
Documents({this.documentId, this.documentName, this.documentLink});
Documents.fromJson(Map<String, dynamic> json) {
documentId = json['document_id'];
documentName = json['document_name'];
documentLink = json['document_link'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['document_id'] = this.documentId;
data['document_name'] = this.documentName;
data['document_link'] = this.documentLink;
return data;
}
}
And this is my logic where I am trying to save data in the hive:
// We get the current app directory
WidgetsFlutterBinding.ensureInitialized();
final appDocDir = await getApplicationDocumentsDirectory();
// We initialize Hive and we give him the current path
Hive
..init(appDocDir.path)
..registerAdapter(DownloadResponseAdapter());
var box = await Hive.openBox('driverData');
//box.put('ew32', DownloadResponse('BMW','test', 2002));
UserInfo userInfo = downloadResponse.userInfo;
AppSetting appSetting = downloadResponse.appSetting;
List<Seals> sealList = downloadResponse.seals;
String success = downloadResponse.success;
String message = downloadResponse.message;
await box.put('driverData', DownloadResponse()
..userInfo = userInfo
..appSetting = appSetting
..seals = sealList
..success = success
..message = message);
print(box.get('driverData'));
I get this exception when box.put() runs:
Unhandled Exception: HiveError: Cannot write, unknown type: UserInfo. Did you forget to register an adapter
My question is how do I create and add multiple adapters with hive as my modal class has multiple classes?
I got the answer of the same. You will have all the adapters available in the automated generated file.
You just need to add them before saving data like this:
Hive
..init(appDocDir.path)
..registerAdapter(DownloadResponseAdapter())
..registerAdapter(UserInfoAdapter())
..registerAdapter(AppSettingAdapter())
..registerAdapter(SealsAdapter())
..registerAdapter(DocumentsAdapter()
);
I'm new to flutter,
My project work when I don't use my class but I want to use class so I change my project for use that and I have some problems.
In my code how to check if the parameter that I use in my function as KeyReference exist in my class ?
And how to use my parameter keyReference for search in my list of user ?
This is my class :
class User{
int type;
String name;
num index;
User({
this.type,
this.name,
this.index,
});
User.fromJson(Map<String, dynamic> map){
type = map['type'];
distance = map['name'];
hausse = map['index'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = Map<String, dynamic>();
data['type'] = this.type;
data['distance'] = this.name;
data['hausse'] = this.index;
}
And this is my function :
static List<User> getListItemsEquality(var value, String keyReference, List<User> items)
{
//**************** Error ****************//
if(items == null)
{
throw MyException.noData();
}
items.forEach((item) {
// =================================================================================
// I have an error on this The method 'containsKey' isn't defined for the type 'User'.
//=================================================================================
if(!item.containsKey(keyReference)){
throw MyException.parameterNotExist();
}
});
//**************** Script ****************//
// =================================================================================
// The getter 'keyReference' isn't defined for the type 'Charge'.
//=================================================================================
return items.where((c) => (c.keyReference == value)).toList();
}
My code works but I want to update this with objects. But I don't see how to add a property value to an object. It must be declared in the constructor ??
For exemple I have a user object with some property.
But in my code I need to classify users by those with the closest salary to a certain value.
For that I want to add an index key which I then use to organize them in order.
This key is just used to classify my users to have the order I want
This index key is not base defined in my object.
My class user :
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},'
'}';
}
void add(String key, dynamic value) {
// ... implementation
}
}
Here an exemple of the function the classify my user and adding the index key in a functions.dart file
List<User> func_orderedItemByClosestSalary(List<User> filteredUsers)
{
switch (filteredUsers.length)
{
case 1:
// One result
print('un seul resultat ...');
filteredUsers[0].index = 0; // Not work for adding the index key
break;
The reason why filteredUsers[0].index = 0; doesn't work is because index isn't defined on Users object. Add index on Users to be able to update its value.
class User{
int index;
String name;
int gender;
num salary;
...
}
I have created multiple models and using json_serialization
Example Company and Employee and many more.
import 'package:json_annotation/json_annotation.dart';
part 'company.g.dart';
#JsonSerializable()
class Company {
Company({this.id, this.name});
String id;
String name;
factory Company.fromJson(Map<String, dynamic> json) => _$CompanyFromJson(json);
Map<String, dynamic> toJson() => _$CompanyToJson(this);
}
import 'package:json_annotation/json_annotation.dart';
part 'employee.g.dart';
#JsonSerializable()
class Employee {
Employee({this.id, this.name, this.email, this.phone, this.photo});
String id;
String name;
String email;
String phone;
String photo;
factory Employee.fromJson(Map<String, dynamic> json) => _$EmployeeFromJson(json);
Map<String, dynamic> toJson() => _$EmployeeToJson(this);
}
Now I want to create a reusable service that can return Stream with type Company, Employee or other types.
I'm using Firebase so the return type is Map.
example service class
class BaseService<T> {
final String collection;
CollectionReference _collectionRef;
FirebaseBase({#required this.collection}) {
_collectionRef = Firestore.instance.collection(collection);
}
Stream<List<T>> find() {
return inColRef.snapshots().map((list) {
return list.documents.map((doc) {
final Map<String, dynamic> data = doc.data;
data['id'] = doc.documentID;
return data;
}).toList();
});
}
}
How do I convert the return data (Map) to a type Company or Employee.
Those class can use the factory of fromJson(data).
But I can't return a T.fromJson(data).
I would like to get
Stream<List<Company>> companies = ServiceBase('companies').find();
Stream<List<Employee>> employees = ServiceBase('employee').find();
This is how you would accomplish the generic assignment using your current code:
class BaseService<T> {
final String collection;
CollectionReference _collectionRef;
FirebaseBase({#required this.collection}) {
_collectionRef = Firestore.instance.collection(collection);
}
Stream<List<T>> find() {
return inColRef.snapshots().map((list) {
return list.documents.map((doc) {
final Map<String, dynamic> data = doc.data;
data['id'] = doc.documentID;
return _build(data) as T;
}).toList();
});
}
dynamic _build(final Map<String, dynamic> data) {
if(collection == 'companies') {
return Company.fromJson(data);
} else if(collection == 'employee') {
return Employee.fromJson(data);
}
... throw if invalid collection passed ? ...
}
}
This would be called as so:
Stream<List<Company>> companies = BaseService<Company>('companies').find();
Stream<List<Employee>> employees = BaseService<Employee>('employee').find();
I would recommend that you should a different object structure with the template method pattern such as:
class CompanyService extends BaseService<Company> {
CompanyService() : super('companies');
Company build(final Map<String, dynamic> data) => Company.fromJson(data);
}
class EmployeeService extends BaseService<Employee> {
EmployeeService() : super('employee');
Employee build(final Map<String, dynamic> data) => Employee.fromJson(data);
}
abstract class BaseService<T> {
final String collection;
CollectionReference _collectionRef;
BaseService(this.collection) {
_collectionRef = Firestore.instance.collection(collection);
}
T build(final Map<String, dynamic> data);
Stream<List<T>> find() {
return inColRef.snapshots().map((list) {
return list.documents.map((doc) {
final Map<String, dynamic> data = doc.data;
data['id'] = doc.documentID;
return build(data);
}).toList();
});
}
}
which would result in the calling code looking something like this:
Stream<List<Company>> companies = CompanyService().find();
Stream<List<Employee>> employees = EmployeeService().find();
I have following Model
product_model.dart
class ProductModel {
String status;
String message;
List<Results> results;
ProductModel({this.status, this.message, this.results});
ProductModel.fromJson(Map<String, dynamic> json) {
status = json['status'];
message = json['message'];
if (json['data'] != null) {
results = new List<Results>();
json['data'].forEach((v) {
results.add(new Results.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
data['message'] = this.message;
if (this.results != null) {
data['data'] = this.results.map((v) => v.toJson()).toList();
}
return data;
}
}
class Results {
String id;
String productCode;
String category;
String title;
String isActive;
Results(
{this.id,
this.productCode,
this.category,
this.title,
this.isActive,
});
Results.fromJson(Map<String, dynamic> json) {
id = json['id'];
productCode = json['product_code'];
category = json['category'];
title = json['title'];
isActive = json['is_active'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['product_code'] = this.productCode;
data['title'] = this.title;
data['category'] = this.category;
data['is_active'] = this.isActive;
return data;
}
}
I have a functionality to save products to favorites. The favorites will be saved as json in a file.
import 'package:example/utils/favstorage.dart';
import 'package:example/models/product_model.dart';
class FavoriteProducts {
FavoritesStorage storage = FavoritesStorage();
List<ProductModel> favorites = [];
Future addFavorite(ProductModel products) async {
favorites.add(products);
await storage.writeFavorites(favorites);
}
}
I want to add product to favorites only if its not there. How can I update the addFavorite method so that if particular id doesnot exist then only proceed adding to favorites.
I am new to flutter. Can anybody help me on this??
You can use and indexWhere to search your list for an item with the same id, like this:
Future addFavorite(ProductModel products) async {
if(favorites.indexWhere((listProduct) => listProduct.id == products.id) == -1){
favorites.add(products);
await storage.writeFavorites(favorites);
}
}
-1 means there was no item, if there was the item it would have returned it from the list.
Understanding your model:
ProductModel has List
Results has id.
How to see if provided ProductModel can be added to favorite:
Take favorites list and look in List.
in each product model liik in List.
for each Results check if there id is same as any Results in List of provided ProductModel to the method.
If every thing is false, add ProductModel to favorite.
Following is the code for your reference:
Future addFavorite(ProductModel products) async {
bool containsId = favorites.any((ProductModel model){
return model.results.any((Results result){
return products.results.any((Results resultInProducts) => resultInProducts.id == result.id);
});
});
if(!containsId){
favorites.add(products);
await storage.writeFavorites(favorites);
}
}
I hope this helps, in case of any doubt please comment. If this answer helps you then please accept and up-vote the answer.