Home > Blockchain >  Pass models as arguments
Pass models as arguments

Time:07-27

In my project, I use the same function over and over again with small differences to get data from firebase, but they use different models, and couldn't figure out how to tell the function to use the correct model.

This is the function that I need to call:

  getDataFromFirebase(firebaseArray, document) async {
    _instance = FirebaseFirestore.instance;
    _localModel = [];
    CollectionReference collectionReference =
        _instance!.collection('collection');
    DocumentSnapshot snapshot = await collectionReference.doc(document).get();
    var data = snapshot.data() as Map;
    var localData;
    localData = data[firebaseArray] as List<dynamic>;
    localData.forEach((element) {
      _localModel.add(model1.fromJson(element));
    });

    return _localModel;
  }

This is the first model class:

class Model1 {
  String name;
  Model1({
    required this.name,
  });
  factory Model1.fromJson(Map<String, dynamic> json) {
    return Model1(
      name: json['name']
    );
  }
}

and model 2 class can have different/more keys:

class Model2 {
  String name;
  int age;
  Model2({
    required this.name,
    required this.age,
  });
  factory Model2.fromJson(Map<String, dynamic> json) {
    return Model2(
      name: json['name'],
      age: json['age'],
    );
  }
}

Is there a way to solve this issue or I do have to write one function for every method?

P.S feel free to ask for any details.

CodePudding user response:

the best way to work with Custom Model

your model should look like this:

class Model {
  final String? name;
  City({
    this.name,
  });

  factory Model.fromFirestore(
    DocumentSnapshot<Map<String, dynamic>> snapshot,
    SnapshotOptions? options,
  ) {
    final data = snapshot.data();
    return Model(
      name: data?['name'],
    );
  }

  Map<String, dynamic> toFirestore() {
    return {
      if (name != null) "name": name,
    };
  }
}

and to work with Firestore should look like this:

final ref = db.collection("collection").withConverter(
      fromFirestore: Model.fromFirestore,
      toFirestore: (Model model, _) => model.toFirestore(),
    );

final docSnap = await ref.doc("doc").get();
final model = docSnap.data(); // Convert to model object
if (model != null) {
  print(model);
} else {
  print("No such document.");
}

this is the best way to work with Custom Model and sorry for my English is not good I hope this helps you

CodePudding user response:

Yes, you can, with the help of generics:

Future<List<TModel>> getDataFromFirebase<TModel>(
      dynamic firebaseArray,
      dynamic document,
      TModel Function(Map<String, dynamic>) converter) async {
    final instance = FirebaseFirestore.instance;
    final localModel = <TModel>[];
    final collectionReference = instance!.collection('collection');
    final snapshot = await collectionReference.doc(document).get();
    final data = snapshot.data() as Map;
    final localData = data[firebaseArray] as List<dynamic>;

    localData.forEach((element) {
      localModel.add(converter(element));
    });

    return localModel;
}

_instance and _localModel seemed to be instance variables. I made them local variables, there is no good reason to have instance variables in this method.

Call it like this:

final models1 = await getDataFromFirebase<Model1>(?, ?, Model1.fromJson);

final models2 = await getDataFromFirebase<Model2>(?, ?, Model2.fromJson);

Obviously, replace the two ? with your parameters, since you did not show the call and the types are dynamic, I have no idea what you pass here. Maybe improve on that with some proper typing of those two parameters.

  • Related