skip to Main Content

I’m building a simple note-taking app, all the notes are being fetched from the backend ‘localhost’. when I first log in and navigate to the notes_screen.dart the app doesn’t show the notes, even though they have been fetched and are being added to the list! but the stranger thing is when I hot reload the app the list does appear!!
here is my NotesScreen:

import 'package:flutter/material.dart';
import 'package:flutter_lorem/flutter_lorem.dart';
import 'package:get/get.dart';
import 'package:logging/logging.dart';
import 'package:notes_app/controllers/login_controller.dart';
import 'package:notes_app/controllers/notes_controller.dart';
import 'package:notes_app/screens/empty_state_screen.dart';
import 'package:notes_app/screens/notes/note_viewer_screen.dart';

import '../../widgets/note_card.dart';
import 'new_note.dart';

class NotesPage extends GetWidget<NotesController> {
  final log = Logger("NotesPage");

  NotesPage({super.key});

  LoginController loginController = Get.find<LoginController>();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
     // some code 
      body: Obx(
        () => controller.isNotesListEmpty()
            ? const Center(child: EmptyState())
            : Padding(
                padding: const EdgeInsets.all(8.0),
                child: ListView.builder(
                    itemCount: controller.notesList.value.length,
                    itemBuilder: (context, index) {
                      return Dismissible(
                        key: UniqueKey(),
                        secondaryBackground: Container(
                          color: Colors.red,
                          child: const Center(
                            child: Icon(Icons.delete_forever),
                          ),
                        ),
                        background: Container(color: Colors.red),
                        onDismissed: (direction) {
                          controller
                              .deleteNote(controller.notesList.value[index].id);
                        },
                        child: NoteCard(
                          note: controller.notesList.value[index],
                          onTap: () async {
                            Get.to(() => NoteViewer(),
                                arguments: controller.notesList.value[index]);
                          },
                          onLongPress: () async {
                            showDialog(
                              context: context,
                              builder: (context) {
                                return AlertDialog(
                                  title: Text('delete_msg'.tr),
                                  actions: [
                                    TextButton(
                                      onPressed: () {
                                        controller.deleteNote(controller
                                            .notesList.value[index].id);
                                      },
                                      child: Text('yes'.tr),
                                    ),
                                    TextButton(
                                      onPressed: () {
                                        Get.back();
                                      },
                                      child: Text('no'.tr),
                                    ),
                                  ],
                                );
                              },
                            );
                          },
                        ),
                      );
                    }),
              ),
      ),
    // some code
    );
  }
}

My NotesController:

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:logging/logging.dart';
import 'package:notes_app/models/new_note_model.dart';
import 'package:notes_app/models/note_model.dart';
import 'package:notes_app/screens/notes/home_screen.dart';
import 'package:notes_app/services/rest_apis.dart';

class NotesController extends GetxController {
  final log = Logger("NotesController");
  Rx<List<Note>> notesList = Rx<List<Note>>([]);
  var titleController = TextEditingController();
  var contentController = TextEditingController();
  RestAPIs restAPI = Get.find<RestAPIs>();

  @override
  void onInit() {
    super.onInit();
    getAllNotes();
    ever(notesList, (callback) => null);
  }

  @override
  void onClose() {
    log.fine("The controller has been deleted");
  }

  bool isNotesListEmpty() {
    if (notesList.value.isEmpty) {
      log.warning("The list notes is Empty!");
      return true;
    } else {
      log.fine("The list notes is not Empty!");
      return false;
    }
  }

  Future getAllNotes() async {
    var results = await restAPI.fetchAllNotes();
    List<Note> notes = List.generate(
      results.length,
      (index) => Note.fromJson(results[index]),
    );
    log.info("The length of the notesList ${notes.length.toString()}");
    notesList.value.addAll(notes);
  }

here is my log when I run the app

[GETX] Instance "NotesController" has been created
[GETX] Instance "NotesController" has been initialized
I/flutter ( 4179): WARNING: 2023-10-15 04:58:45.435093: The list notes is Empty!
I/flutter ( 4179): INFO: 2023-10-15 04:58:45.577467: The length of the notesList 10

as you can see after the ‘NotesController’ is created and initializing the data is saved on the list, note that the log shows that the list is empty because the response hasn’t come through yet, after that the data arrived, but the screen doesn’t update

2

Answers


  1. I had exactly this problem and I solved it by the following :

    in the NotesController

    Future<List<Note>> getAllNotes() async {
        var results = await restAPI.fetchAllNotes();`enter code here`
        List<Note> notes = List.generate(
          results.length,
          (index) => Note.fromJson(results[index]),
        );
        log.info("The length of the notesList ${notes.length.toString()}");
        notesList.value.addAll(notes);
        return notes; // <-- 
      }
    

    in the NotesScreen :

              .
              .
              .
              body: FutureBuilder<List<Note>>(
              future: controller.getAllNotes(),
              builder: (BuildContext context,
                              AsyncSnapshot<List<Note>> snapshot) {
                if (snapshot.hasData) {
                  List<Note> notes= snapshot.data; // use notes instead of controller.notesList.value now
                  return Padding(
                    padding: const EdgeInsets.all(8.0),
                    child: ListView.builder(
                        itemCount: notes.length,
                        itemBuilder: (context, index) {
                          return Dismissible(
                            key: UniqueKey(),
                            secondaryBackground: Container(
                             .
                             .
                             .
                          );
                        }),
                  );
                } else if (snapshot.hasError) {
                  // error widget
                } else {
                  return const Center(child: EmptyState());
                }
              }),
              .
              .
              .
    

    I know there is other solutions but this looks good to me. Hopefully it helps.

    Login or Signup to reply.
  2. You could call just .addAll() not .value.addAll().

    Because .value.addAll() is for only adding,

    but .addAll() of RxList is for adding and refreshing.

    Future getAllNotes() async {
      ...
      // notesList.value.addAll(notes);
      notesList.addAll(notes);
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search