Home > Back-end >  I cant seem to update or edit my Todo app
I cant seem to update or edit my Todo app

Time:06-21

My customer app (whereby you add customer details to a list) successfully adds and deletes data to the data base and sets the state properly. But I cannot get my edit/update function to work.

When I click my edit icon, it successfully shows the details of the existing data, but when I change the detail (text) it does not update to set the state with the new data.

The functions insertTodo, deleteTodo and updateTodo are the problem:

Library

import 'package:sqflite/sqflite.dart';
 import 'package:path/path.dart';

    class Todo {
    int? id;
    final String title;
    final String name;
    final String phone;
    final String fax;
    final String email;
    final String street;
    final String city;
    final String town;
    final String code;
    bool isExpanded;

    Todo({
    this.id,
    required this.title,
    required this.name,
    required this.phone,
    required this.fax,
    required this.email,
    required this.street,
    required this.city,
    required this.town,
    required this.code,
    this.isExpanded = false,
    });

    Map<String, dynamic> toMap() {
    return {
    'id': id,
    'title': title,
    'name': name,
    'phone': phone,
    'fax': fax,
    'email': email,
    'street': street,
    'city': city,
    'town': town,
    'code': code,
    'isExpanded': isExpanded ? 1 : 0,
    };
    }
   
   @override
   String toString() {
   return 'Todo(id : $id, title : $title, name : $name, phone : $phone, fax: $fax, email: 
   $email, street: $street, city: $city, town: $town, code: $code, isExpanded : 
   $isExpanded,)';
   }
    }

 class DatabaseConnect {
 Database? _database;

 Future<Database> get database async {

 final dbpath = await getDatabasesPath();
 const dbname = 'todo.db';
 final path = join(dbpath, dbname);
 _database = await openDatabase(path, version: 1, onCreate: _createDB);

 return _database!;
 }

 Future<void> _createDB(Database db, int version) async {
 await db.execute('''
  CREATE TABLE todo(
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    title TEXT,
    name TEXT,
    phone TEXT,
    fax TEXT,
    email TEXT,
    street TEXT,
    city TEXT,
    town TEXT,
    code TEXT,
    isExpanded INTEGER
  
    )
   ''');
   }

 Future<void> insertTodo(Todo todo) async {
 final db = await database;
 await db.insert(
  'todo',
   todo.toMap(),
   conflictAlgorithm: ConflictAlgorithm.replace,
     );
  }

 Future<void> deleteTodo(Todo todo) async {
 final db = await database;
 await db.delete(
  'todo',
  where: 'id == ?',
  whereArgs: [todo.id],
     );
   }

 Future<void> updateTodo(Todo todo) async {
 final db = await database;
  await db.update(
  'todo',
   todo.toMap(),
   where: 'id = ?',
   whereArgs: [todo.id],
     );
   }

 Future<List<Todo>> getTodo() async {
 final db = await database;

 List<Map<String, dynamic>> items = await db.query(
  'todo',
   orderBy: 'title ASC',
   ); 

   return List.generate(
   items.length,
   (i) => Todo(
    id: items[i]['id'],
    title: items[i]['title'],
    name: items[i]['name'],
    phone: items[i]['phone'],
    fax: items[i]['fax'],
    email: items[i]['email'],
    street: items[i]['street'],
    city: items[i]['city'],
    town: items[i]['town'],
    code: items[i]['code'],
    isExpanded: items[i]['isExpanded'] == 1 ? true : false,
        ),
     );
   }

   Future<List<Todo>> searchContacts(String keyword) async {
   final db = await database;
   List<Map<String, dynamic>> items =
    await db.query('todo', where: 'title LIKE ?', whereArgs: ['$keyword%']);

   return List.generate(
   items.length,
  (i) => Todo(
    id: items[i]['id'],
    title: items[i]['title'],
    name: items[i]['name'],
    phone: items[i]['phone'],
    fax: items[i]['fax'],
    email: items[i]['email'],
    street: items[i]['street'],
    city: items[i]['city'],
    town: items[i]['town'],
    code: items[i]['code'],
    isExpanded: items[i]['isExpanded'] == 1 ? true : false,
         ),
       );
      }
    }

Following is my Customer page, where the functions addItem, deleteItem, updateItem are called that link to the database and also the page where I setState (the mainframe the app goes back to after any action is taken). It portrays the list of data after a new customer detail gets added, existing detail deleted and new info updated:

Customer

import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
import '../customerlist.dart';
import '../library.dart';
import '../user_input.dart';

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

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

 class _CustomerState extends State<Customer> {
  var db = DatabaseConnect();

  void addItem(Todo todo) async {
 await db.insertTodo(todo);
 setState(() {});
  }

  void deleteItem(Todo todo) async {
  await db.deleteTodo(todo);
  setState(() {});
  }

  void updateItem(Todo todo) async {
  await db.updateTodo(todo);
  setState(() {});
   }

   @override
   Widget build(BuildContext context) {
   return Scaffold(
    backgroundColor: Colors.white,
    appBar: AppBar(
      centerTitle: false,
      title: const Padding(
        padding: EdgeInsets.all(50.0),
        child: Text(
          'My Clients',
          style: TextStyle(
              fontSize: 24,
              fontWeight: FontWeight.w600,
              color: Colors.black),
        ),
        ),
      backgroundColor: Colors.white,
      elevation: 0,
      actions: [
        IconButton(
          onPressed: () {
            Navigator.of(context).pushReplacementNamed('/searchPage');
          },
          icon: const Icon(
            Icons.search,
            color: Colors.black,
          ),
        ),
      ]),
     body: Column(
     crossAxisAlignment: CrossAxisAlignment.start,
     children: [
      const Padding(
        padding: EdgeInsets.symmetric(horizontal: 16, vertical: 10),
        child: Text(
          'Company Name',
          style: TextStyle(fontSize: 14, fontWeight: FontWeight.w600),
        ),
      ),
      CustomerList(
        // insertFunction: addItem,
        tobie: deleteItem,
        stella: updateItem,
      ),
    ],

   
    ),
     floatingActionButton: FloatingActionButton(
      backgroundColor: Colors.lightBlueAccent,
      child: const Icon(Icons.add),
      onPressed: () {
        showModalBottomSheet(
          isScrollControlled: true,
          context: context,
          builder: (context) => CustomerProfile(insertFunction: addItem),
        );
      }),
        floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
        );
        }
       }

The next code is my CustomerList where my ListviewBuilder checks for customer data to display. If there are, passes the detail to my CustomerCard page (and populate into a card/ListTile). Also in my CustomerList it passes my additem through function Stella from Customer, through CustomerList, through CustomerCard, to my EditPage:

CustomerList

import 'package:flutter/material.dart';
import 'library.dart';
import 'customercard.dart';

 class CustomerList extends StatelessWidget {

 final Function tobie;
 final Function stella;
 final db = DatabaseConnect();

 CustomerList(
  {required this.stella,
  required this.tobie,
 
  Key? key})
  : super(key: key);

  @override
  Widget build(BuildContext context) {
  return Expanded(
  child: FutureBuilder(
      future: db.getTodo(),
      initialData: const [],
      builder: (BuildContext context, AsyncSnapshot<List> snapshot) {
        var data = snapshot
            .data; // this is the data we have to show. (list of todo)
        var datalength = data!.length;

        return datalength == 0
            ? const Center(
                child: Text('no data found'),
              )
            : ListView.builder(
                itemCount: datalength,
                itemBuilder: (context, i) => CustomerCard(
                  id: data[i].id,
                  title: data[i].title,
                  name: data[i].name,
                  phone: data[i].phone,
                  fax: data[i].fax,
                  email: data[i].email,
                  street: data[i].street,
                  city: data[i].city,
                  town: data[i].town,
                  code: data[i].code,
                  isExpanded: data[i].isExpanded,
                  // insertFunction: insertFunction,
                  janFunction: tobie,
                  simbaFunction: stella,
                ),
              );
           }),
           );
         }
        }

Following is my CustomerCard code, which populates the data into a Card and ListTile. Once again, my updateItem is passed through (simbaFunction:stella):

CustomerCard

import 'package:flutter/material.dart';
import 'library.dart';
import 'package:test_sqlite/edit_input.dart';

class CustomerCard extends StatefulWidget {
 final int id;
 final String title;
 final String name;
 final String phone;
 final String fax;
 final String email;
 final String street;
 final String city;
 final String town;
 final String code;
 bool isExpanded;

 final Function janFunction;
 final Function simbaFunction;

  CustomerCard(
   {required this.id,
   required this.title,
   required this.name,
   required this.phone,
   required this.fax,
   required this.email,
   required this.street,
   required this.city,
   required this.town,
   required this.code,
   required this.isExpanded,
  
   required this.janFunction,
   required this.simbaFunction,
   Key? key})
   : super(key: key);

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

   class _CustomerCardState extends State<CustomerCard> {
   var db = DatabaseConnect();

   @override
   Widget build(BuildContext context) {
   var anotherTodo = Todo(
    id: widget.id,
    title: widget.title,
    name: widget.name,
    phone: widget.phone,
    fax: widget.fax,
    email: widget.email,
    street: widget.street,
    city: widget.city,
    town: widget.town,
    code: widget.code,
    isExpanded: widget.isExpanded);

    return Card(
    child: Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      Theme(
        data: Theme.of(context).copyWith(dividerColor: Colors.transparent),
        child: ExpansionTile(
          initiallyExpanded: false,
          title: Text(
            widget.title,
            style: const TextStyle(
              //fontWeight: FontWeight.bold,
              fontSize: 16,
            ),
          ),
          children: [
            ListTile(
              leading: const Icon(
                Icons.person,
                size: 20,
                color: Colors.teal,
              ),
              visualDensity: const VisualDensity(vertical: -3),
              title: Text(
                widget.name,
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.normal,
                  color: Colors.black,
                ),
              ),
            ),
            ListTile(
              leading: const Icon(
                Icons.phone,
                size: 20,
                color: Colors.teal,
              ),
              visualDensity: const VisualDensity(vertical: -4),
              title: Text(
                widget.phone,
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.normal,
                  color: Colors.black,
                ),
              ),
            ),
            ListTile(
              leading: const Icon(
                Icons.report,
                size: 20,
                color: Colors.teal,
              ),
              visualDensity: const VisualDensity(vertical: -4),
              title: Text(
                widget.fax,
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.normal,
                  color: Colors.black,
                ),
              ),
            ),
            ListTile(
              leading: const Icon(
                Icons.email,
                size: 20,
                color: Colors.teal,
              ),
              visualDensity: const VisualDensity(vertical: -4),
              title: Text(
                widget.email,
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.normal,
                  color: Colors.black,
                ),
              ),
            ),
            ListTile(
              leading: const Icon(
                Icons.place,
                size: 20,
                color: Colors.teal,
              ),
              visualDensity: const VisualDensity(vertical: -4),
              title: Text(
                widget.street,
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.normal,
                  color: Colors.black,
                ),
              ),
            ),
            ListTile(
              leading: const Icon(
                Icons.place,
                size: 20,
                color: Colors.teal,
              ),
              visualDensity: const VisualDensity(vertical: -4),
              title: Text(
                widget.city,
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.normal,
                  color: Colors.black,
                ),
              ),
            ),
            ListTile(
              leading: const Icon(
                Icons.place,
                size: 20,
                color: Colors.teal,
              ),
              visualDensity: const VisualDensity(vertical: -4),
              title: Text(
                widget.town,
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.normal,
                  color: Colors.black,
                ),
              ),
            ),
            ListTile(
              leading: const Icon(
                Icons.code,
                size: 20,
                color: Colors.teal,
              ),
              visualDensity: const VisualDensity(vertical: -4),
              title: Text(
                widget.code,
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.normal,
                  color: Colors.black,
                ),
              ),
            ),
            Row(
              mainAxisAlignment: MainAxisAlignment.end,
              children: [
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: ElevatedButton(
                    onPressed: () {
                      showModalBottomSheet(
                        isScrollControlled: true,
                        context: context,
                        builder: (context) => EditPage(
                          nalaFunction: widget.simbaFunction,
                          variable: anotherTodo,
                          edit: '',
                          edit1: '',
                          edit2: '',
                          edit3: '',
                          edit4: '',
                          edit5: '',
                          edit6: '',
                          edit7: '',
                          edit8: '',
                        ),

                        //updateFunction,
                        //),
                      );
                    },
                    style: ElevatedButton.styleFrom(
                      shape: const StadiumBorder(),
                      primary: Colors.white,
                      elevation: 0,
                      padding: const EdgeInsets.symmetric(
                          horizontal: 2, vertical: 2),
                    ),
                    child: const Icon(
                      Icons.edit,
                      size: 20,
                      color: Colors.grey,
                    ),
                  ),
                ),
              ],
            ),
          ],
          leading: const IconButton(
            icon: Icon(
              Icons.place,
              color: Colors.blue,
              size: 20,
            ),
            onPressed: null,
            alignment: Alignment.center,
          ),
          trailing: IconButton(
            onPressed: () {
              widget.janFunction(anotherTodo);
            },
            icon: const Icon(
              Icons.delete,
              color: Colors.red,
              size: 20,
            ),
          ),
        ),
        ),
       ],
       ),
       );
      }
     }

Lastly, my EditPage. When I open it, the existing customer data in the SQLite database automatically displays correctly. Each Textfield has its own onChanged. Once I press the Elevated button, the bottomModalSheet closes properly (pop), but the new data does not actually update. This is the problem.

EditPage

import 'package:flutter/material.dart';
import 'library.dart';
import 'package:flutter/cupertino.dart';

class EditPage extends StatelessWidget {
 final Todo variable;
 final Function nalaFunction;
 String edit;
 String edit1;
 String edit2;
 String edit3;
 String edit4;
 String edit5;
 String edit6;
 String edit7;
 String edit8;

  late final textController = TextEditingController(text: variable.title);
  late final nameController = TextEditingController(text: variable.name);
  late final phoneController = TextEditingController(text: variable.phone);
  late final faxController = TextEditingController(text: variable.fax);
  late final emailController = TextEditingController(text: variable.email);
  late final streetController = TextEditingController(text: variable.street);
  late final cityController = TextEditingController(text: variable.city);
  late final townController = TextEditingController(text: variable.town);
  late final codeController = TextEditingController(text: variable.code);

  EditPage(
 
  {Key? key,
  required this.nalaFunction,
  required this.variable,
  required this.edit,
  required this.edit1,
  required this.edit2,
  required this.edit3,
  required this.edit4,
  required this.edit5,
  required this.edit6,
  required this.edit7,
  required this.edit8,
   }) : super(key: key);

   @override
   Widget build(BuildContext context) {
   return Container(
   padding: const EdgeInsets.all(30.0),
   decoration: const BoxDecoration(
    color: Colors.white,
    borderRadius: BorderRadius.only(
      topLeft: Radius.circular(30.0),
      topRight: Radius.circular(30.0),
      ),
    ),
    child: Scaffold(
    appBar: AppBar(
      backgroundColor: Colors.white,
      elevation: 0,
      title: const Padding(
        padding: EdgeInsets.all(15.0),
        child: Text(
          'Client Details',
          style: TextStyle(color: Colors.black, fontSize: 24),
        ),
      ),
      leading: GestureDetector(
        onTap: () {
          Navigator.of(context).pushReplacementNamed('/homePage');
        },
        child: const Icon(
          Icons.arrow_back,
          color: Colors.black,
        ),
      ),
    ),
    body: SingleChildScrollView(
      child: Container(
        color: Colors.white,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            TextField(
              controller: textController,
              autofocus: true,
              textAlign: TextAlign.left,
              decoration: const InputDecoration(
                hintText: 'Company Name',
                hintStyle: TextStyle(color: Colors.grey),
              ),
              onChanged: (String? value) {
                edit = value!;
              },
            ),
            TextField(
              controller: nameController,
              autofocus: true,
              textAlign: TextAlign.left,
              decoration: const InputDecoration(
                hintText: ' Contact Name & Surname',
                hintStyle: TextStyle(color: Colors.grey),
              ),
              onChanged: (String? value1) {
                edit1 = value1!;
              },
            ),
            TextField(
              controller: phoneController,
              autofocus: true,
              textAlign: TextAlign.left,
              decoration: const InputDecoration(
                hintText: ' Contact Number',
                hintStyle: TextStyle(color: Colors.grey),
              ),
              onChanged: (String? value2) {
                edit2 = value2!;
              },
            ),
            TextField(
              controller: faxController,
              autofocus: true,
              textAlign: TextAlign.left,
              decoration: const InputDecoration(
                hintText: 'Fax Number',
                hintStyle: TextStyle(color: Colors.grey),
              ),
              onChanged: (String? value3) {
                edit3 = value3!;
              },
            ),
            TextField(
              controller: emailController,
              autofocus: true,
              textAlign: TextAlign.left,
              decoration: const InputDecoration(
                hintText: 'Email Address',
                hintStyle: TextStyle(color: Colors.grey),
              ),
              onChanged: (String? value4) {
                edit4 = value4!;
              },
            ),
            TextField(
              controller: streetController,
              autofocus: true,
              textAlign: TextAlign.left,
              decoration: const InputDecoration(
                hintText: 'Street Name',
                hintStyle: TextStyle(color: Colors.grey),
              ),
              onChanged: (String? value5) {
                edit5 = value5!;
              },
            ),
            TextField(
              controller: cityController,
              autofocus: true,
              textAlign: TextAlign.left,
              decoration: const InputDecoration(
                hintText: ' City',
                hintStyle: TextStyle(color: Colors.grey),
              ),
              onChanged: (String? value6) {
                edit6 = value6!;
              },
            ),
            TextField(
              controller: townController,
              autofocus: true,
              textAlign: TextAlign.left,
              decoration: const InputDecoration(
                hintText: 'Town',
                hintStyle: TextStyle(color: Colors.grey),
              ),
              onChanged: (String? value7) {
                edit7 = value7!;
              },
            ),
            TextField(
              controller: codeController,
              autofocus: true,
              textAlign: TextAlign.left,
              decoration: const InputDecoration(
                hintText: ' Code',
                hintStyle: TextStyle(color: Colors.grey),
              ),
              onChanged: (String? value8) {
                edit8 = value8!;
              },
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context);
                var valueTodo = Todo(
                    title: edit,
                    name: edit1,
                    phone: edit2,
                    fax: edit3,
                    email: edit4,
                    street: edit5,
                    city: edit6,
                    town: edit7,
                    code: edit8,
                    isExpanded: false);
                nalaFunction(valueTodo);
              },
              child: Padding(
                padding: const EdgeInsets.fromLTRB(0, 10, 0, 0),
                child: Container(
                  decoration: BoxDecoration(
                    color: Theme.of(context).primaryColor,
                    borderRadius: BorderRadius.circular(15),
                  ),
                  padding: const EdgeInsets.symmetric(
                      horizontal: 25, vertical: 10),
                  child: const Text(
                    'Update',
                    textAlign: TextAlign.center,
                    style: TextStyle(
                      color: Colors.white,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                ),
              ),
            ),
            ],
          ),
        ),
      ),
     ),
    );
 }
}

I think the problem is either:

  1. My function in my database is incorrect.
  2. Somehow the data (updateItem) in Customer page does not link with updateTodo in the database.
  3. The updateItem data is passed through all the widgets to EditPage incorrectly.
  4. My code in EditPage (ElevatedButton onPressed is wrong).
  5. The argument (edit '', edit1 '' and so on) in CustomerCard page that route to EditPage is wrong.

CodePudding user response:

I have managed to finally resolve the problem. I have replaced my ElevatedButton with a GestureDetector and also removed onChaged from my TextFields, thus also removing all my edit parameters.

My updateFunction and updateItem function was actually working just fine all along. I previously used GestureDetector with onTap and a variable (updateTodo) with my textEditingControllers, but since I could not make this work, I tried ElevateButton with the onChanged, which also did not work. So, moving back to GestureDetector, I realized that I never assigned an 'id' to my variable ' updateTodo'. I only had my TextEditingController. Now, in my Sql Database, the database is updated using 'Where: id', but since I did not assign an 'id' to my text, I effectively returned Null everytime I updated.

Here is the snippet of code for GetureDetector before the fix,

GestureDetector(
              onTap: () {
                Navigator.pop(context);
                var updateTodo = Todo(
                    
                    title: textController.text,
                    name: nameController.text,
                    phone: phoneController.text,
                    fax: faxController.text,
                    email: emailController.text,
                    street: streetController.text,
                    city: cityController.text,
                    town: townController.text,
                    code: codeController.text,
                    isExpanded: false);
                nalaFunction(updateTodo);
              },

and here the same code after the fix:

GestureDetector(
              onTap: () {
                Navigator.pop(context);
                var updateTodo = Todo(
                     id: id,
                    title: textController.text,
                    name: nameController.text,
                    phone: phoneController.text,
                    fax: faxController.text,
                    email: emailController.text,
                    street: streetController.text,
                    city: cityController.text,
                    town: townController.text,
                    code: codeController.text,
                    isExpanded: false);
                nalaFunction(updateTodo);
              },

and the code for passing the 'id' in CustomerCard class through to EditPage:

class CustomerCard extends StatefulWidget {
final int id;
final String title;
final String name;
final String phone;
final String fax;
final String email;
final String street;
final String city;
final String town;
final String code;
bool isExpanded;

final Function janFunction;
final Function simbaFunction;

 CustomerCard(
 {required this.id,
 required this.title,
 required this.name,
 required this.phone,
 required this.fax,
 required this.email,
 required this.street,
 required this.city,
 required this.town,
 required this.code,
 required this.isExpanded,

and ..

Row(mainAxisAlignment: MainAxisAlignment.end,
      children: [
      Padding(
      padding: const EdgeInsets.all(8.0),
       child: ElevatedButton(
         onPressed: () {
         showModalBottomSheet(
         isScrollControlled: true,
         context: context,
         builder: (context) => EditPage(
          nalaFunction: widget.simbaFunction,
          variable: anotherTodo,
          id: widget.id,
          ),

                        //updateFunction,
                        //),
                      );
                    },

and passing the 'id' through to the EditPage so that it can be reached by the GestureDetector on the same page:

class EditPage extends StatelessWidget {
 final Todo variable;
 final Function nalaFunction;
 final int id;

 late final textController = TextEditingController(text: variable.title);
 late final nameController = TextEditingController(text: variable.name);
 late final phoneController = TextEditingController(text: variable.phone);
 late final faxController = TextEditingController(text: variable.fax);
 late final emailController = TextEditingController(text: variable.email);
 late final streetController = TextEditingController(text: variable.street);
 late final cityController = TextEditingController(text: variable.city);
 late final townController = TextEditingController(text: variable.town);
 late final codeController = TextEditingController(text: variable.code);

 EditPage({Key? key,
 required this.nalaFunction,
 required this.variable,
 required this.id,
 }) : super(key: key);

This resolved my problem and my app now update new customer data perfectly.

  • Related