skip to Main Content

I’m working on a Flutter project in which the architecture forces me to use an instance of a class, say UserModel, as a value attached to the BuildContext. In this way, I can access that class in every part of the app.

Anyway, there are moments in which I want to update the UserModel, and not only by changing the value of some of the fields, but updating all of them. At this moment, I am using an horrible function, let’s call that updateUser(final UserModel newInstance). It follows an example.

class UserModel {
  String name, surname;

  UserModel({required this.name, required this.surname});

  void updateUser(final UserModel newInstance) {
    name = newInstance.name;
    surname = newInstance.surname;
  }
}

The main problem with this solution is that it often happens that I add some fields to the UserModel class, but I forgot to add them to updateUser. Also, the solution I am using looks horrible.

I know that many of you could say that I should enclose the instance of UserModel in a UserModelProvider class and just replace the value of the userModel field. This would not be compatible with the architecture of the software I am developing, so please don’t suggest me that.

2

Answers


  1. Chosen as BEST ANSWER

    I got it sorted out. The main point to understand is to use reflection, the ability of a program to examine and modify its own structure, behavior, and metadata at runtime.

    To do so, I edit my updateUser function to be able to loop through the class variables and set them in the new instance. Here is the result.

    import 'dart:mirrors';
    
    class UserModel {
      String name, surname;
    
      UserModel({required this.name, required this.surname});
    
      void updateUser(final UserModel newInstance) {
        final InstanceMirror thisInstanceMirror = reflect(this);
        final InstanceMirror newInstanceMirror = reflect(newInstance);
    
        final ClassMirror classMirror = thisInstanceMirror.type;
    
        for (final DeclarationMirror otherField in classMirror.declarations.values) {
          // We exclude fields that are not variables, like functions
          if (otherField is VariableMirror) {
            // We exclude constant, final and static variables
            if (!otherField.isConst && !otherField.isFinal && !otherField.isStatic) {
              // Finally we update the field with the new value
              thisInstanceMirror.setField(otherField.simpleName,
                newInstanceMirror.getField(otherField.simpleName).reflectee);
            }
          }
        }
      }
    
      @override
      String toString() {
        return "Name: $name, Surname: $surname";
      }
    }
    

    So now I can use an instance of the class to update itself, for instance by fetching new values from Firestore. It follows an example of the functioning.

    void main() {
      final UserModel user = UserModel(name: "John", surname: "Doe");
      final UserModel user2 = UserModel(name: "Jane", surname: "Doe");
    
      print(user); // Name: John, Surname: Doe
      print(user2); // Name: Jane, Surname: Doe
    
      user.updateUser(user2);
    
      print(user); // Name: Jane, Surname: Doe
    }
    

    And this is crucial if my UserModel is being served by Provider, and therefore attached to the BuildContext.


  2. To be honest, it’s hard to understand your issue.

    If I’m not wrong, you are looking for copyWith method.

    class UserModel {
      String name, surname;
    
      UserModel({required this.name, required this.surname});
    
      UserModal copyWith({
         String? name,
         String? surname,
      }) => UserModel(
              name: name?? this.name,
              surname: surname ?? this.surname);
    }
    

    With this method, you will be able to update one or both variable.

    final  foo = UserModel("foo","foo2");
    
    final boo = foo.copyWith(); // boo = UserModel("foo","foo2");
    
    final yoo = foo.copyWith(name:"yoo"); // yoo = UserModel("yoo","foo2");
    
    // update foo
     foo = foo.copyWith(surname:"update foo"); // foo = UserModel("foo","update foo");
    

    Updated

    I don’t know why you force to update it, the concept is the same.

    class UserModel {
    ...
     UserModel updateWITHMODELASYOUWANT( UserModel data){
      return UserModel(
        name: data.name, 
        surname: data.surname,
     }
    }
    
    

    As I said in the comments, you update the instance, not the object model.

    foo is an instance of UserModel

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search