javascriptflutterdartflutter-dependencies

Flutter Widget state not consistent while updating checkbox list array


I have a stateful widget that utilizes flutter_multi_select_items package. The issue I'm having is the alternating state only changes once upon first click. I want the checkboxes to be unclicked by default, yet the selected input requires a value and it remains true after each state change event. How do I properly alternate adding/removing id values from the checkbox array and keeping the state in sync with the values being added and removed?

Logs

flutter: true
flutter: 1
flutter: removing add on
flutter: []

Performing hot reload...                                                
Reloaded 1 of 1718 libraries in 426ms (compile: 21 ms, reload: 156 ms, reassemble: 174 ms).
flutter: false
flutter: adding add-on
flutter: [1]
flutter: true
flutter: removing add on
flutter: []
flutter: true

class _AddServiceState extends State<AddService> {
  final MultiSelectController<dynamic> _multiSelectcontroller = MultiSelectController();
   List<dynamic> checkAddons = [];
  Widget build(BuildContext context) {
   List<dynamic> _addOns = widget.service_profile['service_add_ons'];
   return MaterialApp(
        home: Scaffold(
         appBar: AppBar(title: 'Adjust your add-ons')
        ),
        body: SingleChildScrollView(
          physics: AlwaysScrollableScrollPhysics(),
          child: Column(children: <Widget>[
                ElevatedButton(
                                  onPressed: () {
                                    _multiSelectcontroller.selectAll();
                                  },
                                  child: const Text('Select All')),
                              Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    MultiSelectCheckList(
                                      maxSelectableCount: 5,
                                      textStyles: const MultiSelectTextStyles(
                                          selectedTextStyle: TextStyle(
                                              color: Colors.white,
                                              fontWeight: FontWeight.bold)),
                                      itemsDecoration: MultiSelectDecorations(
                                          selectedDecoration: BoxDecoration(
                                              color: Colors.indigo
                                                  .withOpacity(0.8))),
                                      listViewSettings: ListViewSettings(
                                          separatorBuilder: (context, index) =>
                                              const Divider(
                                                height: 0,
                                              )),
                                      controller: _multiSelectcontroller,
                                      items: List.generate(
                                          _addOns.length,
                                          (index) => CheckListCard(
                                              value: _addOns[index]['id'],
                                              title:
                                                  Text(_addOns[index]['title']),
                                              subtitle:
                                                  Text(_addOns[index]['price']),
                                              selectedColor: Colors.white,
                                              checkColor: Colors.indigo,
                                              selected:
                                                  checkedAddons.indexOf(_addOns[index]['id'], index) == index,
                                              enabled: true,
                                              checkBoxBorderSide:
                                                  const BorderSide(
                                                      color: Colors.blue),
                                              shape: RoundedRectangleBorder(
                                                  borderRadius:
                                                      BorderRadius.circular(
                                                          5)))),
                                      onChange:
                                          (allSelectedItems, selectedItem) {
                                        if (allSelectedItems.isNotEmpty) {
                                          checkedAddons = [];
                                          checkedAddons
                                              .addAll(allSelectedItems);
                                          return;
                                        }

                                        print(checkedAddons
                                            .contains(selectedItem));
                                        if (checkedAddons
                                            .contains(selectedItem)) {
                                          print('removing add on');

                                          setState(() {
                                            checkedAddons.removeWhere((item) => item == selectedItem);
                                          });

                                          print(checkedAddons);
                                        } else {
                                          print('adding add-on');
                                          setState(() {
                                            checkedAddons.add(selectedItem);
                                          });
                                          print(checkedAddons);
                                        }
                                      },
                                      onMaximumSelected:
                                          (allSelectedItems, selectedItem) {
                                        //    CustomSnackBar.showInSnackBar(
                                        //       'The limit has been reached', context);
                                      },
                                    )
       
]
         )
     )
  }
});

Solution

  • If you put checkAddons inside the build method when you use setState(), the method build is recalled, then the checkAddons will be reset to the default value of [], which will make this error. The solution is to put checkAddons outside the build method. There is an example for flutter_multi_select_items:

    import 'package:flutter/material.dart';
    import 'package:flutter_multi_select_items/flutter_multi_select_items.dart';
    
    class MultiSelectExample extends StatefulWidget {
      @override
      State<MultiSelectExample> createState() => _MultiSelectExampleState();
    }
    
    class _MultiSelectExampleState extends State<MultiSelectExample> {
      final MultiSelectController _controller = MultiSelectController();
      final List<Map<String, String>> items = [
        {'id': '1', 'title': 'Apple'},
        {'id': '2', 'title': 'Banana'},
        {'id': '3', 'title': 'Cherry'},
        {'id': '4', 'title': 'Date'},
        {'id': '5', 'title': 'Elderberry'},
      ];
    
      List<dynamic> selectedItems = []; // Manage items selected
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: const Text('Multi Select Example'),
          ),
          body: Column(
            children: [
              const SizedBox(height: 16),
              Row(
                children: [
                  Padding(
                    padding: const EdgeInsets.all(16.0),
                    child: ElevatedButton(
                      onPressed: () {
                        ScaffoldMessenger.of(context).showSnackBar(
                          SnackBar(content: Text('Selected items: $selectedItems')),
                        );
                      },
                      child: const Text('Show Selected Items'),
                    ),
                  ),
                  ElevatedButton(
                    onPressed: () {
                      _controller.selectAll();
                      setState(() {
                        selectedItems = items.map((e) => e['id']).toList();
                      });
                      ScaffoldMessenger.of(context).showSnackBar(
                        const SnackBar(content: Text('All items selected')),
                      );
                    },
                    child: const Text('Select All'),
                  ),
                ],
              ),
              Expanded(
                child: MultiSelectCheckList(
                  controller: _controller,
                  items: List.generate(
                    items.length,
                    (index) => CheckListCard(
                      value: items[index]['id'],
                      title: Text(items[index]['title']!),
                      checkColor: Colors.white,
                      selectedColor: Colors.indigo,
                    ),
                  ),
                  textStyles: const MultiSelectTextStyles(
                    selectedTextStyle: TextStyle(
                      color: Colors.white,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  itemsDecoration: MultiSelectDecorations(
                    selectedDecoration: BoxDecoration(
                      color: Colors.indigo.withOpacity(0.8),
                    ),
                  ),
                  onChange: (allSelectedItems, selectedItem) {
                    setState(() {
                      selectedItems = allSelectedItems;
                    });
                    print('Selected items: $selectedItems');
                  },
                ),
              ),
            ],
          ),
        );
      }
    }