Ive created an app with Flutter bloc package.Ive created a screen named learning_dashboard_screen which contains a list fetched from a server. inside that same screen I have a filter button which on press will show a filter screen using the bottom sheet widget.
it has got different categories for the list to be filtered. In the learning_dashboard_screen_state screen Ive got a Map named filteroptions which is of type Map<String, Map<String, dynamic>>.This map is used to populate the checkboxes by mapping the map with the checkbox widget.
part of 'learning_dashboard_screen_bloc.dart';
class LearningDashboardScreenState extends Equatable {
static ScrollController controller = ScrollController();
final int courseLimit = 3;
final List<GPaginatedCoursesData_paginatedCourses_data> courses;
final DataRetrievalStatus initialCoursesStatus;
final Map<String, Map<String, dynamic>> filterOption;
Map<String, Map<String, dynamic>> getFilterOption() {
return filterOption;
}
final int currPage;
final bool hasNextPage;
final DataRetrievalStatus moreCoursesStatus;
LearningDashboardScreenState(
{this.courses = const [],
this.initialCoursesStatus = DataRetrievalStatus.NOT_INITIALIZED,
this.filterOption = const {
"Certificate Provider": {"NVQ": false, "City and Guilds": false},
"Course Language": {"Sinhala": false, "English": false, "Tamil": false},
"Duration": {"6 Months": false, "8 Months": false, "1Year": false},
"Category": {
"Baby Care": false,
"First Aid": false,
"Adult Care": false,
"Mental Care": false,
"Physiotherapy": false,
"Baby First Aid": false,
"Light Housekeeping": false,
"Assist Methods": false
}
},
this.currPage = 0,
this.hasNextPage = false,
this.moreCoursesStatus = DataRetrievalStatus.NOT_INITIALIZED});
@override
List<Object?> get props => [
courses,
filterOption,
initialCoursesStatus,
courseLimit,
currPage,
hasNextPage,
moreCoursesStatus
];
LearningDashboardScreenState copyWith(
{List<GPaginatedCoursesData_paginatedCourses_data>? course,
DataRetrievalStatus? courseStatus,
int? currPage,
bool? hasNextPage,
Map<String, Map<String, dynamic>>? filterOption,
DataRetrievalStatus? moreCourseStatus}) {
return LearningDashboardScreenState(
courses: course ?? this.courses,
filterOption: filterOption ?? this.filterOption,
initialCoursesStatus: courseStatus ?? this.initialCoursesStatus,
currPage: currPage ?? this.currPage,
hasNextPage: hasNextPage ?? this.hasNextPage,
moreCoursesStatus: moreCourseStatus ?? this.moreCoursesStatus);
}
ScrollController getScrollController() {
return controller;
}
}
what I want is to change the boolean value of the filteroption map in the state according to the chackbox value. For that what Ive done is ,
1.I created an event in the event class ,
class CheckBoxValueChangedEvent extends LearningDashboardScreenEvent {
String filterOption;
String filterValue;
bool isChecked;
CheckBoxValueChangedEvent({required this.filterOption,required this.filterValue,required
this.isChecked});
@override
List<Object?> get props => [];
}
I called that event in the on press of the checkbox
CheckBox( label: entry.key, onChanged: (isChecked) { context .read<LearningDashboardScreenBloc>() .add(CheckBoxValueChangedEvent(filterOption: widgetName, filterValue: entry.key, isChecked: isChecked)); }, key: GlobalKey<CheckBoxState>(), initValue: entry.value, ),
3.In the bloc class I wrote the function to change the bool value in the state class and emit the state,
void _onCheckBoxValueChangedEvent(CheckBoxValueChangedEvent event,
Emitter<LearningDashboardScreenState> emit) {
Map<String, Map<String, dynamic>> filterOption = {};
filterOption=new Map<String, Map<String, dynamic>>.from(state.filterOption);
if (event.isChecked = true) {
filterOption[event.filterOption]![event.filterValue] = true;
} else {
filterOption[event.filterOption]![event.filterValue] = false;
}
emit(state.copyWith(filterOption: filterOption));
}
My problem is when I tick a checkbox I get,
Error: Unhandled error Unsupported operation: Cannot modify unmodifiable map occurred in
Instance of 'LearningDashboardScreenBloc'.
CodePudding user response:
The problem is that when you declare a map as const
you cannot modify the map.
In your constructor filterOption
has a default value that is const
:
LearningDashboardScreenState(
{this.courses = const [],
this.initialCoursesStatus = DataRetrievalStatus.NOT_INITIALIZED,
this.filterOption = const {
"Certificate Provider": {"NVQ": false, "City and Guilds": false},
"Course Language": {"Sinhala": false, "English": false, "Tamil": false},
"Duration": {"6 Months": false, "8 Months": false, "1Year": false},
"Category": {
"Baby Care": false,
"First Aid": false,
"Adult Care": false,
"Mental Care": false,
"Physiotherapy": false,
"Baby First Aid": false,
"Light Housekeeping": false,
"Assist Methods": false
},
},
this.currPage = 0,
this.hasNextPage = false,
this.moreCoursesStatus = DataRetrievalStatus.NOT_INITIALIZED}
);
A possible workaround would be to define the map literal in the initializer list, rather than as a default parameter (so that it doesn't need to be const).
LearningDashboardScreenState(
{this.courses = const [],
this.initialCoursesStatus = DataRetrievalStatus.NOT_INITIALIZED,
Map<String, Map<String, dynamic>>? filterOption,
this.currPage = 0,
this.hasNextPage = false,
this.moreCoursesStatus = DataRetrievalStatus.NOT_INITIALIZED}
): this.filterOption = filterOption ??
{
"Certificate Provider": {"NVQ": false, "City and Guilds": false},
"Course Language": {
"Sinhala": false,
"English": false,
"Tamil": false
},
"Duration": {
"6 Months": false,
"8 Months": false,
"1Year": false
},
"Category": {
"Baby Care": false,
"First Aid": false,
"Adult Care": false,
"Mental Care": false,
"Physiotherapy": false,
"Baby First Aid": false,
"Light Housekeeping": false,
"Assist Methods": false
}
};