I am very new to Dart and Flutter, and I've been trying to make two classes (SuccessState and ErrorState) that implement an abstract class (DataState) with optional named parameters. For some reason, whenever I call the super constructor in SuccessState and ErrorState, I get an undefined_named_parameter error on the "data" parameter in the SuccessState constructor and "status" and "msg" parameters in the ErrorState constructor. Any input is greatly appreciated, thanks.
abstract class DataState<T> {
final T? data;
final int? status;
final String? msg;
const DataState({this.data, this.status, this.msg});
}
class SuccessState<T> implements DataState<T> {
const SuccessState(T data) : super(data: data);
#override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class ErrorState<T> implements DataState<T> {
const ErrorState(int status, String msg) : super(status: status, msg: msg);
#override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
You want to extend SuccessState and ErrorState to DataState.
abstract class DataState<T> {
final T? data;
final int? status;
final String? msg;
const DataState({this.data, this.status, this.msg});
}
class SuccessState<T> extends DataState<T> {
SuccessState(T data) : super(data: data);
#override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
class ErrorState<T> implements DataState<T> {
const ErrorState(int status, String msg) : super();
#override
noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}
The problem is you are using implements rather than extends. You don't inherit the super constructor when using implements.
The thing you are doing wrong is your are implementing as you have to extend DataState class then issue will resolved
'class ErrorState implements DataState'
Change to class ErrorState extends DataState
Related
I am still a beginner with BLoC architecture. So far the UI updates when using int, bool, and other basic data types. But when it comes to Maps it really confuses me. My code basically looks like this:
my state
enum TalentStatus { initial, loading, loaded, error }
class TalentState extends Equatable {
const TalentState({
required this.talentStatus,
this.selectedService = const {},
required this.talents,
this.test = 0,
});
final TalentStatus talentStatus;
final Talents talents;
final Map<String, Service> selectedService;
final int test;
TalentState copyWith({
TalentStatus? talentStatus,
Talents? talents,
Map<String, Service>? selectedService,
int? test,
}) =>
TalentState(
selectedService: selectedService ?? this.selectedService,
talentStatus: talentStatus ?? this.talentStatus,
talents: talents ?? this.talents,
test: test ?? this.test,
);
#override
List<Object> get props => [talentStatus, talents, selectedService, test];
}
my event
abstract class TalentEvent extends Equatable {
const TalentEvent();
#override
List<Object> get props => [];
}
class TalentStarted extends TalentEvent {}
class TalentSelectService extends TalentEvent {
const TalentSelectService(
this.service,
this.talentName,
);
final Service service;
final String talentName;
}
and my bloc
class TalentBloc extends Bloc<TalentEvent, TalentState> {
TalentBloc(this._talentRepository)
: super(TalentState(
talentStatus: TalentStatus.initial, talents: Talents())) {
on<TalentSelectService>(_selectService);
}
final TalentRepository _talentRepository;
Future<void> _selectService(
TalentSelectService event,
Emitter<TalentState> emit,
) async {
state.selectedService[event.talentName] = event.service;
final selectedService = Map<String, Service>.of(state.selectedService);
emit(
state.copyWith(
selectedService: selectedService,
),
);
}
}
whenever an event TalentSelectService is called BlocBuilder doesn't trigger, what's wrong with my code?
Your Service object must be comparable. One suggestion is that it extends Equatable. Either way it have to implement (override) the == operator and hashCode
The reason your BlocBuilder doesn't trigger is (probably) that it doesn't recognize that there has been a change in the Map.
I'm trying to use Bloc package for my state management in my Flutter app. I have situation where I have two list within the same screen, and I am confused should I use two cubits for each list or I can make something like in code bellow where I used one cubit for both lists. I wanna know is this way of structuring code correct? In this image is the sketch of the screen.
abstract class CounterState extends Equatable {
const CounterState({this.valOne, this.valTwo, this.error});
final int? valOne;
final int? valTwo;
final String? error;
#override
List<Object?> get props => [valOne, valTwo, error];
}
class CounterInitial extends CounterState {}
class ValOneSuccess extends CounterState {
const ValOneSuccess(int? val, int? valTwo)
: super(valOne: val, valTwo: valTwo);
}
class ErrorState extends CounterState {
const ErrorState(int? val, int? valTwo, String error)
: super(valOne: val, valTwo: valTwo, error: error);
}
class CounterCubit extends Cubit<CounterState> {
CounterCubit() : super(CounterInitial());
void loadData() async {
int valOne;
int valTwo;
emit(CounterInitial());
try {
valOne = 2;
emit(ValOneSuccess(valOne, state.valTwo));
///If error is thrown
//throw Exception('ValueOne exception');
} catch (e) {
print(e);
emit(ErrorState(state.valOne, state.valTwo, e.toString()));
}
try {
valTwo = 1;
emit(ValOneSuccess(state.valOne, valTwo));
///If error is thrown
//throw Exception('ValueTwo exception');
} catch (e) {
state.error != null
? emit(ErrorState(
state.valOne, state.valTwo, 'Exception on both values'))
: emit(ErrorState(state.valOne, state.valTwo, e.toString()));
}
}
}
I need to understand this code, resoCoder did it on DDD Playlist. why does he implements IEntity inside freezed?
The code is:
#freezed
abstract class TodoItem with _$TodoItem implements IEntity {
const factory TodoItem({
#required UniqueId id,
#required TodoName name,
#required bool done,
}) = _TodoItem;
factory TodoItem.empty() => TodoItem(
id: UniqueId(),
name: TodoName(''),
done: false,
);
}
}
IEntity code is:
abstract class IEntity {
UniqueId get id;
}
UniqueId Code is:
class UniqueId extends ValueObject<String> {
#override
final Either<ValueFailure<String>, String> value;
// We cannot let a simple String be passed in. This would allow for possible non-unique IDs.
factory UniqueId() {
return UniqueId._(
right(Uuid().v1()),
);
}
/// Used with strings we trust are unique, such as database IDs.
factory UniqueId.fromUniqueString(String uniqueIdStr) {
assert(uniqueIdStr != null);
return UniqueId._(
right(uniqueIdStr),
);
}
const UniqueId._(this.value);
}
It ensures consistency; TodoItem must implement everything as per IEntity.
Let's imagine one day you want to add an attribute "createdAt" to IEntity: in this case, you will have to add "createdAt" to every class that implements IEntity across the project, otherwise the compiler will let you know you're missing something :D
Some code now.
The result would be
abstract class IEntity {
UniqueId get id;
int get createdAt; // let's keep it "int" for the example purpose
}
then you would have to update the freezed class too
#freezed
abstract class TodoItem with _$TodoItem implements IEntity {
const factory TodoItem({
#required UniqueId id,
#required int createdAt,
#required TodoName name,
#required bool done,
}) = _TodoItem;
factory TodoItem.empty() => TodoItem(
id: UniqueId(),
createdAt: 1234,
name: TodoName(''),
done: false,
);
}
}
so I don't have any idea how to take argument from mine Cubit state which is AnswerPicked in this case, there is a code from states file.
part of 'answer_cubit.dart';
abstract class AnswerState extends Equatable {
const AnswerState();
#override
List<Object> get props => [];
}
class AnswerInitial extends AnswerState {}
class AnswerPicked extends AnswerState {
final String answer;
AnswerPicked({
this.answer,
});
String toString() => '{AnswerPicked: $answer}';
}
I want to use it in Cubit function right there:
part 'answer_state.dart';
class AnswerCubit extends Cubit<AnswerState> {
final ExamScoreCubit scoreCubit;
AnswerCubit({
#required this.scoreCubit,
}) : super(AnswerInitial());
List<String> userAnswersList = [];
void pickAnswer(String answer) {
emit(AnswerInitial());
emit(AnswerPicked(answer: answer));
}
void takeAnswer(String questionAnswer, int type) {
if(state is AnswerPicked){
userAnswersList.add(state.answer); // state.answer don't work
scoreCubit.checkAnswer(AnswerPicked().answer, questionAnswer, type); // AnswerPicked().answer don't work
}
emit(AnswerInitial());
}
}
In void takeAnswer() I don't want to pass it throw argument inside the widget tree using context. Any ideas how to do it?
userAnswersList.add((state as AnswerPicked) .answer);
I am trying to figure out the best way to define my Search Bloc's State to preserve text property (search key) across all state classes.
Currently, it looks like this:
import 'package:equatable/equatable.dart';
import 'package:project/models/searchResults.dart';
class SearchState extends Equatable {
SearchState([List props = const []]) : super(props);
}
class SearchStateEmpty extends SearchState {
final String text;
SearchStateEmpty({this.text});
#override
String toString() => 'SearchStateEmpty';
}
class SearchStateLoading extends SearchState {
final String text;
SearchStateLoading({this.text});
#override
String toString() => 'SearchStateLoading';
}
class SearchStateSuccess extends SearchState {
final String text;
final List<RestaurantSearchItem> items;
SearchStateSuccess({this.text, this.items}) : super([text, items]);
#override
String toString() => 'SearchStateSuccess { items: ${items.length} }';
}
class SearchStateError extends SearchState {
final String text;
final String error;
SearchStateError({this.text, this.error}) : super([text, error]);
#override
String toString() => 'SearchStateError';
}
Is there a better way of using text property than defining it throughout all state classes?
This would not be as bad as it is now if I wouldn't have to use currentState property every time an event does not have it. For example:
SearchStateEmpty(text: currentState.text);
...
SearchStateLoading(text: event.text);
...
SearchStateSuccess(text: currentState.text, items: results.items);
I was looking for examples in Flutter docs but all I was able to find out was that I should either use different blocs for it or ditch equatable (which I want to keep since it's pretty nice to have).
Any suggestions with examples would be highly appreciated. Thanks.
The way I was doing it was sort of antipattern. With some help, I was able to find a more clean way to use the current state in my state classes.
Code now looks like this:
class SearchState extends Equatable {
final String text;
SearchState(this.text,
[List<RestaurantSearchItem> items = const [], String error = ''])
: super([text, items, error]);
}
class SearchStateEmpty extends SearchState {
SearchStateEmpty({String text})
: super(text); // Here I want to use text from SearchState
SearchStateEmpty.fromState(SearchState state) : super(state.text);
#override
String toString() => 'SearchStateEmpty';
}
class SearchStateLoading extends SearchState {
final String text;
SearchStateLoading({this.text})
: super(text); // Here I want to set text that comes from event
#override
String toString() => 'SearchStateLoading';
}
class SearchStateError extends SearchState {
final String error;
SearchStateError({this.error, String text}) : super(text, [], error);
// Text comes from SearchState, error comes from event
SearchStateError.fromState(SearchState state, {this.error})
: super(state.text, [], error);
#override
String toString() => 'SearchStateError';
}
class SearchStateSuccess extends SearchState {
final List<RestaurantSearchItem> items;
SearchStateSuccess({this.items, String text}) : super(text, items, null);
SearchStateSuccess.fromState(SearchState state, {this.items})
: super(state.text, items, null);
#override
String toString() => 'SearchStateSuccess { items: ${items.length} }';
}