Home > OS >  Flutter Hive: values are not deleted
Flutter Hive: values are not deleted

Time:01-29

I am testing Hive NoSQL Database. I have succeeded in creating a database, putting a value, and getting a value.

  1. However, I failed to delete the value. I've done a lot of searching, but I can't figure it out.

  2. Also, when saving the value of TextFormField using Button, Get.Back(); was used using GetX, but it did not work. The value is saved, but the screen is not popped. So, I popped it using Navigation and it worked. I don't know what was the cause.

I'd appreciate it if you could tell me what the problem is.

home_screen.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:hive_test1/component/todo_card.dart';
import 'package:hive_test1/db/database.dart';
import 'package:hive_test1/scr/form_screen.dart';

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

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

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          Get.to(() => FormScreen());
        },
        child: Icon(Icons.add),
      ),
      appBar: AppBar(
        centerTitle: true,
        title: const Text('Hive Test'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: ValueListenableBuilder(
            valueListenable: Hive.box<Todos>('testTable').listenable(),
            builder: (context, Box<Todos> box, child) {
              return ListView.separated(
                itemCount: box.length,
                itemBuilder: (_, index) {
                  var item = box.get(index);

                  if (item == null) {
                    return Center(
                        child: Container(
                      child: Text('null'),
                    ));
                  } else {
                    return TodoCard(
                        title: item.title,
                        note: item.note,
                        dateTime: item.dateTime,
                        id: item.id,
                        onPressed: () {
                          setState(() {
                            box.deleteAt(item.id);  // This is not working.
                          });
                        });
                  }
                },
                separatorBuilder: (_, index) {
                  return const Padding(
                    padding: EdgeInsets.symmetric(vertical: 10),
                    child: Divider(),
                  );
                },
              );
            }),
      ),
    );
  }
}

form_screen.dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:hive_test1/db/database.dart';

class FormScreen extends StatefulWidget {
  const FormScreen({Key? key}) : super(key: key);

  @override
  _FormScreenState createState() => _FormScreenState();
}

class _FormScreenState extends State<FormScreen> {
  GlobalKey<FormState> formKey = GlobalKey();

  String? title;
  String? note;
  DateTime? dateTime;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: const Text('Form Screen'),
      ),
      body: Form(
        key: formKey,
        child: Padding(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            children: [
              renderTextFormField(
                  label: 'Title',
                  hintText: 'Please enter a title',
                  onSaved: (val) {
                    setState(() {
                      title = val;
                    });
                  },
                  validator: (val) {
                    if (val.length < 1) {
                      return 'Please enter a title';
                    }
                    return null;
                  }),
              renderTextFormField(
                  label: 'Note',
                  hintText: 'Please enter a value',
                  onSaved: (val) {
                    setState(() {
                      note = val;
                    });
                  },
                  validator: (val) {
                    if (val.length < 1) {
                      return 'Please enter a note';
                    }
                    return null;
                  }),
              saveButton(),
            ],
          ),
        ),
      ),
    );
  }

  renderTextFormField({
    required String label,
    required onSaved,
    required validator,
    required hintText,
  }) {
    return Column(
      children: [
        Row(
          children: [
            Text(
              label,
              style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
            ),
          ],
        ),
        const SizedBox(
          height: 5,
        ),
        TextFormField(
          style: TextStyle(fontSize: 20),
          autovalidateMode: AutovalidateMode.always,
          onSaved: onSaved,
          validator: validator,
          decoration: InputDecoration(
            contentPadding: EdgeInsets.all(8),                  
            hintText: hintText,           
            border: const OutlineInputBorder(),
          ),
        ),
      ],
    );
  }

  saveButton() {
    return Row(
      children: [
        Expanded(
          child: ElevatedButton(
            onPressed: () async {
              var box = Hive.box<Todos>('testTable');
              if (formKey.currentState!.validate()) {               
                formKey.currentState?.save();              
                int id = 0; 
                if (box.isNotEmpty) {
                  final prevItem = box.getAt(box.length - 1);
                  id = prevItem!.id   1;
                }
                box.put(
                  id,
                  Todos(
                    title: title!,
                    note: note!,
                    id: id,
                    dateTime: dateTime = DateTime.now(),
                  ),
                );
                Get.snackbar(
                  'Saved!',
                  'Your form has been saved!',
                );
                print(title);

                Navigator.of(context).pop();  // this is working
                // Get.Back();  <- Not Working

              } else if (formKey.currentState?.validate() == null) {
                Get.snackbar(
                  "Required",
                  "All fields are required!",
                  snackPosition: SnackPosition.BOTTOM,
                  backgroundColor: Colors.white.withOpacity(0.5),
                  icon: Icon(
                    Icons.warning_amber_rounded,
                    color: Colors.red,
                  ),
                );
              }
            },
            child: const Text(
              'Save',
              style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
            ),
          ),
        ),
      ],
    );
  }
}

database.dart

import 'package:hive/hive.dart';

part 'database.g.dart';

@HiveType(typeId: 1)
class Todos {

  Todos(
      {required this.title,
      required this.note,
      required this.id,
      required this.dateTime});

  @HiveField(0) 
  int id;

  @HiveField(1)
  String title;

  @HiveField(2)
  String note;

  @HiveField(3)
  DateTime dateTime;
}

CodePudding user response:

There was no answer to my #1 question, so I tried to find the answer myself. I haven't found an answer for the 2nd one yet.

Answer 1 should have declared VoidCallback instead of Function when declaring a Function.

Here's the code:

import 'package:flutter/material.dart';

class TodoCard extends StatefulWidget {
  final String title;
  final String note;
  final int id;
  final DateTime dateTime;
  final VoidCallback onPressed;  
// This is answer. VoidCallback instead of Function

renderIconButton() {
    return IconButton(
      onPressed: widget.onPressed,  // This is answer.
      icon: const Icon(
        Icons.delete,
        color: Colors.red,
        size: 25,
      ),
    );
  }
                  return TodoCard(
                      title: item.title,
                      note: item.note,
                      dateTime: item.dateTime,
                      id: item.id,
                      onPressed: () => box.deleteAt(index),
                    );

CodePudding user response:

  1. You are not deleting with index I guess. If that so, to delete with id use .delete instead of .deleteAt method like:

    onPressed: () async {
                   setState(() {
                         await box.delete(item.id);
                       });
                     }
    
  2. SnackBars and dialogs are considered as routes in GetX. Therefore, you need to close that route using Get.back() if they are open in order to navigate away from the containing screen/page:

    Get.back(); // to close the opened snackbar or dialog Get.back(); // to close the current page and go back

You need to use Get.back() twice essentially. But there's a problem with this. Calling Get.back() twice immediately closes your snackbar and never shown. You could use Future.delayed to overcome this:

await Future.delayed(Duration(seconds: 3), ()=> Get.back()); // allows the snackbar to be displayed for 3 seconds before closing

Get.back(); // Go back
  •  Tags:  
  • Related