pmatatias
pmatatias

Reputation: 4404

copyWith() method for Inheritance class on dart

I want to implement copyWith() method for my class. Since its inhirited class, i got error:

The member being overridden.

enter image description here

my basemodel

class BaseData {
  int id;
  String? createdAt, updatedAt;

  BaseData({this.id = 0, this.createdAt, this.updatedAt});
  BaseData copyWith({
    int? id,
    String? createdAt,
    String? updatedAt,
  }) =>
      BaseData(
          id: id ?? this.id,
          createdAt: createdAt ?? this.createdAt,
          updatedAt: updatedAt ?? this.updatedAt);
}

and I have another class that extend to my BaseData model

class QcData extends BaseData{
  String name;
  QcData ({this.name =""});

  @override
  QcData copyWith({
  String? name
  }){
    return QcData(name: name ?? this.name);
 }
}

How to create copyWith() method for my model class?

Thanks in advance.

Upvotes: 4

Views: 3039

Answers (3)

par
par

Reputation: 17724

Here's a pattern I came up with that seems to work pretty well:

class BaseData {
    final int baseValue;

    BaseData([Map map = const {}, BaseData? data]) :
        baseValue = map['baseValue'] ?? data?.baseValue ?? 0;

    T copyWith<T extends BaseData>(Map map) {
        return BaseData(map, this) as T;
    }
}

class ExtendedData extends BaseData {
    final int extendedValue;

    ExtendedData([super.map, ExtendedData? super.data]) :
        extendedValue = map['extendedValue'] ?? data?.extendedValue ?? 0;

    @override
    T copyWith<T extends BaseData>(Map map) {
        return ExtendedData(map, this) as T;
    }
}

One thing to notice with the above however is that since we assign to a member using the construct map[key] ?? defaultValue we can't easily clear a value.

So a bit of additional code I use says, "if the key exists in map, unconditionally set its value." This lets us put a key with a null value in the map parameter dictionary and use that to clear a field.

Updated with this functionality I add the following:

extension MapExtension on Map {
    T? valueOf<T>(Object key, [Object? defaultValue]) {
        return containsKey(key) ? this[key] : defaultValue;
    }
}

Then the constructors change to:

    BaseData([Map map = const {}, BaseData? data]) :
        baseValue = map.valueOf('baseValue', data?.baseValue ?? 0);

and

    ExtendedData([super.map, ExtendedData? super.data]) :
        extendedValue = map.valueOf('extendedValue', data?.extendedValue);

Upvotes: 0

Md. Yeasin Sheikh
Md. Yeasin Sheikh

Reputation: 63614

We also need to pass data on while creating QcData(child). I prefer modifying constructor this way.

  const QcData({
    this.name = "",
    super.id,
    super.createdAt,
    super.updatedAt,
  });

Now we have access on copyWith method these property, another cause is I like to use const constructor with final fields.

 @override
  QcData copyWith({
    String? name,
    int? id,
    String? createdAt,
    String? updatedAt,
  }) {
    return QcData(
      name: name ?? this.name,
      id: id ?? this.id,
      createdAt: createdAt ?? this.createdAt,
      updatedAt: updatedAt ?? this.updatedAt,
    );
  }

The models will be

class BaseData {
  final int id;
  final String? createdAt;
  final String? updatedAt;

  const BaseData({this.id = 0, this.createdAt, this.updatedAt});

  BaseData copyWith({
    int? id,
    String? createdAt,
    String? updatedAt,
  }) {
    return BaseData(
      id: id ?? this.id,
      createdAt: createdAt ?? this.createdAt,
      updatedAt: updatedAt ?? this.updatedAt,
    );
  }
}

class QcData extends BaseData {
  final String name;

  const QcData({
    this.name = "",
    super.id,
    super.createdAt,
    super.updatedAt,
  });

  @override
  QcData copyWith({
    String? name,
    int? id,
    String? createdAt,
    String? updatedAt,
  }) {
    return QcData(
      name: name ?? this.name,
      id: id ?? this.id,
      createdAt: createdAt ?? this.createdAt,
      updatedAt: updatedAt ?? this.updatedAt,
    );
  }
}

Upvotes: 3

Gwhyyy
Gwhyyy

Reputation: 9166

inheritance means that a class member's definitions should remain the same when you extend, or implement a base class, in your case by doing the:

  @override
   QcData copyWith({
   String? name
  }){
     return QcData(name: name ?? this.name);
 }

this method declaration is not the same as the BaseData's since they take different sets of arguments, you should remain the arguments the same as the BaseData, so your code should be this in order to work:

class QcData extends BaseData {
  String name;
  QcData({this.name = ""});

  @override
  QcData copyWith({
    int? id,
    String? createdAt,
    String? updatedAt,
  }) {
    return QcData(name: name ?? this.name);
  }
}

Upvotes: 3

Related Questions