Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Flutter/Dart – Cannot modify unmodifiable map error

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.

enter image description here

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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 => [];
  }
  1. 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'.

>Solution :

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
              }
            };
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading