Home > OS >  How to update todo item?
How to update todo item?

Time:05-20

When clicking on a todo item, an edit window opens, where the user can make changes and save them. I wrote an update function in ChangeNotifier, but when I click on save, an error pops up: This happen because you used a 'BuildCOntext' that does not include the provider of you choice. But the rest of the code in the provider works. Only the update function does not work. What could be the problem? My ChangeNotifier:

class ListModel extends ChangeNotifier {
  List<EventModel> eventList = [];

  void addEventToList() {
    EventModel eventModel = EventModel(
      title: 'Event title ${eventList.length   1}',
      detail: 'Event text ${eventList.length   1}',
      id: '${eventList.length   1}',
    );
    eventList.add(eventModel);

    notifyListeners();
  }

  EventModel? getEvent(String? id) {
    return eventList.firstOrNullWhere((event) => event.id == id);
  }

  void updateList(EventModel eventModel, String title, String detail) {
    eventModel.title = title;
    eventModel.detail = detail;

    notifyListeners();
  }
}

My modal window:

class EditEventBottomSheet extends StatefulWidget {
  final EventModel event;

  const EditEventBottomSheet({Key? key, required this.event}) : super(key: key);

  @override
  State<EditEventBottomSheet> createState() => _EditEventBottomSheetState();
}

class _EditEventBottomSheetState extends State<EditEventBottomSheet> {
  late final titleCntrl = TextEditingController(text: widget.event.title);
  late final detailCntrl = TextEditingController(text: widget.event.detail);

  @override
  Widget build(BuildContext context) {
    return Container(
      height: 300,
      color: Colors.amber,
      child: Center(
        child: Padding(
          padding: const EdgeInsets.all(20),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            mainAxisSize: MainAxisSize.min,
            children: [
              const Text(
                'Change Event',
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 10),
              TextField(
                controller: titleCntrl,
              ),
              const SizedBox(height: 10),
              TextFormField(
                controller: detailCntrl,
              ),
              const SizedBox(height: 10),
              ElevatedButton(
                child: const Text('Save Edits'),
                onPressed: () {
                  Provider.of<ListModel>(context, listen: false).updateList(
                      widget.event, titleCntrl.text, detailCntrl.text);
                  // widget.event.title = titleCntrl.text;
                  Navigator.pop(context);
                },
              ),
              ElevatedButton(
                child: const Text('Close BottomSheet'),
                onPressed: () => Navigator.pop(context),
              )
            ],
          ),
        ),
      ),
    );
  }
}

My main.dart:

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ChangeNotifierProvider(
        create: (BuildContext context) => ListModel(),
        child: const HomeScreen(),
      ),
    );
  }
}

CodePudding user response:

Ok, so if you set your ChangeNotifierProvider in your home, only his child (the HomeScreen) gonna get the ListModel(), that's why in your EditEventBottomSheet the BuildContext doesn't find the Provider, but if you want to use it in another Class Widget, you have to "re-create" another ChangeNotifierProvider in your EditEventBottomSheet, like this : (you don't create another ListModel, you only put the one you had already created)

ChangeNotifierProvider.value(
  value: ListModel(),
  child: EditEventBottomSheet(),
)

But don't worry about that, for that I recommend you to put your Provider globally, that is to say, that ALL your application has access to it, and how? Well, instead of creating it in your body, you create it in your MaterialApp.

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider( // something like this
      create: (BuildContext context) => ListModel(),
      child: MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: const HomeScreen(),
      ),
    );  
  }
}
  • Related