0

Im making my first TODO app, and im struggling with updating my app after user made a new note. I want a child class(HomeBody) of HomePage be updated after user click save and Navigator.pop() from NewNotePage.

Here is my parent class HomePage form where I want to update child and child class is HomeBody as a body of Scaffold.

class HomePage extends StatefulWidget {
  const HomePage({super.key});
  static const String routeName = '/home';

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    ...
      // ----------------------Center-------------------------------
      body: const HomeBody(),
      // ----------------------BOTTOM--------------------------------
      bottomNavigationBar: const HomeBottomAppBar(),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.pushNamed(context, NewNotePage.routeName).then((_) {
            setState(() {});
            print("Action after Navigator.pop()");
          });
        },
        child: const Icon(Icons.create),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
    );
  }
}

Child class looks like this, I want to update this class to show new note that user made.

class HomeBody extends StatefulWidget {
  const HomeBody({super.key});

  @override
  State<HomeBody> createState() => _HomeBodyState();
}

class _HomeBodyState extends State<HomeBody> {
  @override
  Widget build(BuildContext context) {
    return ListView(
      padding: const EdgeInsets.all(5),
      children: <Widget>[
        if (notesList.isNotEmpty)
          for (var note in notesList)
            NoteWidget(
                note: note,
                onDeletePressed: () {
                  DataDB.delete(note: note, context: context).then((value) {
                    setState(() {});
                  });
                })
        else ...[
          Container(
            alignment:
                AlignmentGeometry.lerp(Alignment.center, Alignment.center, 0),
            child: Text(
              "Add your first note",
              style: Theme.of(context)
                  .textTheme
                  .titleMedium!
                  .copyWith(color: Colors.black.withOpacity(0.5)),
            ),
          ),
        ],
      ],
    );
  }
}

And here is state of NewNotePage where user make note and save it and page pop back to HomePage.

@override
  Widget build(BuildContext context) {
    return Scaffold(
      ...
      // ----------------------Center-------------------------------
      body: NewNoteBody(controller: contentController),
      // ----------------------BOTTOM--------------------------------
      bottomNavigationBar: const BottomAppBar(
        notchMargin: 4,
        clipBehavior: Clip.antiAlias,
      ),
      floatingActionButton: FloatingActionButton(
        tooltip: 'save',
        onPressed: () async {
          if (titleController.text.isNotEmpty ||
              contentController.text.isNotEmpty) {
            NoteModel note = NoteModel(
              title: titleController.text,
              content: contentController.text,
            );
            await DataDB.addNote(note: note).then((value) {
              Navigator.pop(context);
            });
          } else {
            Navigator.pop(context);
          }
        },
        child: const Icon(
          Icons.done_rounded,
          size: 32,
        ),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
    );
  }
Kris
  • 13
  • 4
  • I'm wondering where you created the notesList that you are looping through in the HomeBodyState? also, are you updating it when you add the note to the database? – M. Abdel-Ghani Aug 03 '23 at 17:36
  • @M.Abdel-Ghani notesList is a global variable and I update it in DataDB.addNote(). `await DatabaseHelper.instance.insert(note: note).then((value) { notesList.add(value);` – Kris Aug 03 '23 at 20:37

1 Answers1

0

OK I will answer my own question cause I found what a silly mistake I made. The method with passing controller to child widget works really well, it didn't worked for be because initialization of controller was in initState in a child and I just forgot to restart app...

Solution to my problem I found here: https://stackoverflow.com/a/60869283/21395456

So I will show how I passed a controller to child.

class HomePageController {
  late void Function() updateBodyState;
}

class HomePage extends StatelessWidget {
  HomePage({super.key});
  static const String routeName = '/home';

  final HomePageController myController = HomePageController();

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Scaffold(
      backgroundColor: theme.colorScheme.primaryContainer,
      // ----------------------TOP--------------------------------
      appBar: AppBar(
        title: const Text(
          'Notes',
          style: TextStyle(color: Colors.black, fontWeight: FontWeight.bold),
        ),
      ),
      // ----------------------Center-------------------------------
      body: HomeBody(controller: myController),
      // ----------------------BOTTOM--------------------------------
      bottomNavigationBar: const HomeBottomAppBar(),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Navigator.pushNamed(context, NewNotePage.routeName).then((_) {
            myController.updateBodyState();
            print("setStates");
          });
        },

Here is child class:

class HomeBody extends StatefulWidget {
  const HomeBody({super.key, required this.controller});
  final HomePageController controller;

  @override
  State<HomeBody> createState() => _HomeBodyState();
}

class _HomeBodyState extends State<HomeBody> {
  @override
  void initState() {
    super.initState();
    widget.controller.updateBodyState = () {
      setState(() {});
    };
  }

I think mostly understand what I did, so if there will be any questions, I can try answer.

Kris
  • 13
  • 4