Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a base factory and override it on child class in Flutter

So I have a class like Question like bellow:

@JsonSerializable()
class Question {
  String id;
  String content;

  Question({this.id, this.content});

  factory Question.fromJson(Map<String, dynamic> json) =>
      _$QuestionFromJson(json);
  Map<String, dynamic> toJson() => _$QuestionToJson(this);
}

Please keep in mind that those _$QuestionFromJson and _$QuestionToJson comes from this library https://pub.dev/packages/json_serializable

Say I have many class like that which have a fromJson factory and a toJson method. I want to create a base class that contains those 2 method. A base model is easy for toJson as bellow:

abstract class BaseModel {
  Map<String, dynamic> toJson();
}

But what about the factory method, I have no idea how to declare them then override it simply like:

@override
factory Question.fromJson(Map<String, dynamic> json) =>
      _$QuestionFromJson(json);

EDIT: My idea of using this is because I want to create a converter utility that I only need to pass in the class of the result like Converter.listFromJson<MyClass>(jsonString). For now, the helper is:

static List<T> listFromJson<T>(jsonString, Function mappingFunction) {
   return myJsonMap.map(mappingFunction).cast<T>().toList();
}

so I have to map each item by passing the map function every time I use this helper method:

Converter.listFromJson<Question>(
          jsonMap, (item) => Question.fromJson(item));

There'are a few more class that needs to be convert to the list like this. I want to reuse the method without the (item) => Question.fromJson(item) method part. That's why I want to create a base class that have the factory fromJson method so that I can use it in the converter

return myJsonMap.map((item) => BaseModel.fromJson(item)).cast<T>().toList();

then I just simply call

Converter.listFromJson<Question>(jsonMap);

Thank you for your time.

like image 895
Tran Hoai Nam Avatar asked May 22 '19 06:05

Tran Hoai Nam


2 Answers

i don't know if i got you correctly, that's what i understood from your question

abstract class BaseModel{
  BaseModel();

  BaseModel.fromJson(Map<String,dynamic> json);
}

class Question extends BaseModel{
  final String id;
  final String name;

  Question({this.id,this.name}): super();

  @override
  factory Question.fromJson(Map<String, dynamic> json) {
    return Question(
        id: json['id'],
        name: json['name']
    );
  }
}

void main(){
  Map<String,dynamic> json = {'id': "dsajdas",'name': 'test'};
  Question question = Question.fromJson(json);
  print('question: ${question.id}');
}
like image 95
Sami Kanafani Avatar answered Oct 14 '22 21:10

Sami Kanafani


That was my approach but you can't do such a thing. There is a workaround by declaring .fromJson(json) in a variable. Look at my sample codes, hope you can get an idea.

    class Categories {
      final String id;
      String name;
      String image;
    
      Categories({this.id, this.name, this.image});
      Categories.fromJson(dynamic json)
          : id = json['id'],
            name = json['name'],
            image = json['image'];
    }
    
    class CategoriesModel extends AppModel<Categories> {
      List<Categories> list = [];
      Function fromJson = (dynamic json) => Categories.fromJson(json);
    
    }
    
    class AppModel<T> {
      List<T> list = [];
      Function fromJson;
    
      List<T> getList() {
        if (this.list.isNotEmpty) return this.list;
        List<dynamic> list = GetStorage().read('tableName');
        list.forEach((data) {
          this.list.add(fromJson(data));
        });
        return this.list;
      }
    }
like image 34
Christopher Natan Avatar answered Oct 14 '22 21:10

Christopher Natan