I am building an app with Flutter using BLOC Architecture with the flutter_bloc package.
I have a data class for an object, which looks like this example:
class MyClass {
int? id;
List<MyOtherClass> myOtherClasses = [];
MyClass();
MyClass._(this.id, this.myOtherClasses);
MyClass copyWith({int? id, List<MyOtherClass>? myOtherClasses}) {
return MyClass._(
id ?? this.id,
myOtherClasses ?? this.myOtherClasses,
);
}
}
class MyOtherClass {
int value;
MyOtherClass(this.value);
}
Now I a Screen that shows the values of the class, and a Dialog to edit it. To store the state, I am using a Cubit, that looks like this:
#immutable
abstract class MyClassState {
final MyClass myClass;
MyClassState(this.myClass);
}
class MyClassInitial extends MyClassState {
MyClassInitial() : super(MyClass());
}
class MyClassEditing extends MyClassState {
final MyClass editingMyClass;
MyClassEditing(MyClass myClass, this.editingMyClass) : super(myClass);
}
class MyClassChanged extends MyClassState {
MyClassChanged(MyClass myClass) : super(myClass);
}
class MyClassCubit extends Cubit<MyClassState> {
MyClassCubit() : super(MyClassInitial());
void editMyClass({int? id, List<MyOtherClass>? myOtherClasses}) {
emit(MyClassEditing(state.myClass,
state.myClass.copyWith(id: id, myOtherClasses: myOtherClasses)));
}
void saveChanges() {
if (state is MyClassEditing)
emit(MyClassChanged((state as MyClassEditing).editingMyClass));
}
void discardChanged() {
emit(MyClassChanged(state.myClass));
}
}
So, basically, what I am trying to achieve here is to story a backup of MyClass in the MyClassEditing state in order to be able to discard the changes I made to MyClass. When I call the constructor of MyClassEditing here in this line: emit(MyClassEditing(state.myClass, state.myClass.copyWith(id: id, myOtherClasses: myOtherClasses)));, the state should contain the initial instance of MyClass without any changes, and the copy of the initial MyClass instance with the changes applied. But somehow, both instances have the changes applied, and I just don't get why this happens. Am I doing something wrong copying the instance?
Probably, the issue might be lists, if you make shallow copy of them.
Related
class Car {
var name;
var model;
var cc;
Car(this.name, this.model, this.cc);
printAll() {
print(name);
print(model);
print(cc);
}
print(name); //Showing Error
}
void main() {
var obj = Car("Marcedes", "Class E", 5000);
obj.printAll();
}
Why i can't do any kind of operation outside the method body. The code generates error in compilation which given bellow. The code write in Dartpad.
Error in Compilation. The output show
Error compiling to JavaScript:
main.dart:1:7:
Error: The non-abstract class 'Car' is missing implementations for these members:
You have declared a method named print with a parameter called name but without a method body, i.e. an abstract method. In order to instantiate a class, Dart obviously has to know what the method body is, therefore you cannot instantiate an abstract class.
You need to do two things:
Because you have an abstract method, and abstract methods are only allowed in abstract classes, you need to mark Car as abstract.
You need to create a subclass of Car that overrides print with an implementation, and then instead instantiate that class.
Something like this:
abstract class Car {
var name;
var model;
var cc;
Car(this.name, this.model, this.cc);
printAll() {
print(name);
print(model);
print(cc);
}
print(name); // Abstract method `print` with no implementation
}
class ConcreteCar extends Car {
ConcreteCar(name, model, cc): super(name, model, cc);
#override
print(name) {
// Implementation of `print`
}
}
void main() {
var obj = ConcreteCar("Mercedes", "Class E", 5000);
obj.printAll();
}
Note: I left the implementation of print empty because I didn't understand the reason for the abstract print method and what the goal of the design is. But it should be trivial for you to fill out the missing pieces.
Lets say that I have an abstract class
abstract class OnClickHandler {
void doA();
void doB();
}
I have a class
class MyClass {
OnClickHandler onClickHandler;
MyClass({
this.onClickHandler
})
void someFunction() {
onClickHandler.doA();
}
}
And I have a class
class Main implements onClickHandler {
// This throws me an error
MyClass _myClass = MyClass(onClickHandler = this); // <- Invalid reference to 'this' expression
#override
void doA() {}
#override
void doB() {}
}
How can I say that use the same implementations that the Main class has? or is there an easier/better way to do this?
Your problem is that this does not yet exists since the object are still being created. The construction of Dart objects is done in two phases which can be difficult to understand.
If you change you program to the following it will work:
abstract class OnClickHandler {
void doA();
void doB();
}
class MyClass {
OnClickHandler onClickHandler;
MyClass({this.onClickHandler});
void someFunction() {
onClickHandler.doA();
}
}
class Main implements OnClickHandler {
MyClass _myClass;
Main() {
_myClass = MyClass(onClickHandler: this);
}
#override
void doA() {}
#override
void doB() {}
}
The reason is that code running inside { } in the constructor are executed after the object itself has been created but before the object has been returned from the constructor.
I want to initialize a parameter within my constructor depending on the value of another parameter.
So depending on if the oldEmployee is not null I should add him to the availableEmployees list otherwise take the availableEmployees list as is.
The reason I want to do this within this class is, that I have read that when using Bloc I should do the computing within the Bloc's State instead of doing this in the UI.
Here is how my class looks like:
class ShiftCreatedOrEdited extends ShiftsState {
final List<Employee> availableEmployees;
final Employee oldEmployee;
const ShiftCreatedOrEdited({
this.availableEmployees,
this.oldEmployee,
});
List<Employee> addOldEmployeeToTheAvailableEmployees(List<Employee> availableEmployees, Employee oldEmployee) {
if (oldEmployee != null) {
List<Employee> hList = availableEmployees;
hList.add(oldEmployee);
return hList;
} else {
return availableEmployees;
}
}
}
How about this:
void main() {}
class Employee {}
class ShiftsState {}
class ShiftCreatedOrEdited {
final Employee oldEmployee;
final List<Employee> availableEmployees;
ShiftCreatedOrEdited(
Employee _oldEmployee, List<Employee> _availableEmployees)
: this.availableEmployees =
_availableEmployees + (_oldEmployee != null ? [_oldEmployee] : []),
this.oldEmployee = _oldEmployee;
}
I'm new to OOP and dart. I posted the code below that "works" but intellisense doesn't work with it.
Problem:
The state getter is dynamic because accessing settings.state.entity won't even compile if the return type is EntityState. I thought the if (settings.state is EntityLoaded<Settings>) type check would allow me to access .entity. but I guess that's not how it works.
How do I get intellisense to work again?
abstract class EntityState {}
class EntityEmpty extends EntityState {}
class EntityLoaded<T> extends EntityState {
final T entity;
EntityLoaded(this.entity);
}
class SettingsProvider extends ChangeNotifier {
// ----------------------------------> _state could be either EntityEmpty or EntityLoaded<T>
EntityState _state = EntityEmpty();
SettingsProvider(this._state);
// EntityState get state => _state --> doesn't let me access .entity code block below.
get state => _state; // -------------> works without intellisense
}
final settings = Provider.of<SettingsProvider>(context);
if (settings.state is EntityLoaded<Settings>) {
print(settings.state.entity);
}
Figured it out.
Dart typecasting error
I had to change is Type check to:
final state = Provider.of<SettingsProvider>(context).state;
if (state is EntityLoaded<Settings>) {
print(state.entity);
}
then I can access .entity without warning.
I have a method which i'd like to refactor
Basically i want to split the top level method in a abstract and a final part.
The method in question is overridden in quite a few places where additional functionality is added, but eventualy the super call is always made.
The code now basically look like:
(not all Extending classes override but those that do, do it this way)
class Base {
public Object getStuff(String key) {
out = //code to get data from the Database.
return out
}
class Extended1 extends Base {
public Object getStuff(String key) {
if("some_non_db_value".equals(key)) {
return "some custom stuff";
}
return super.getStuff(key);
}
}
What i'd like as a result would be something like:
class Base {
public final Object getStuff(String key) {
out = getCustom(key);
if(out != null) {
return custom;
}
out = //code to get data from the Database.
return out
}
public abstract Object getCustom(String key);
}
class Extended1 extends Base {
public Object getCustom(String key) {
if("some_non_db_value".equals(key)) {
return "some custom stuff";
}
return null;
}
}
I was hoping there would be a refactor action (or partial refactor) to get to (or closer to) this point.
I would first rename getStuff() to getCustom() which would take care of all the extended classes. Then changing the Base class should be relatively easy.