Reputation: 29
I did somehow managed to get the database contents to show via listview. However, its not doing it properly. As soon as i run the emulator the contents stored in the database should appear, but they don't. It also shows that the database is empty even though it clearly isn't. But once i add a new item to the database and click save, everything shows up (except the one i last added and it shows up on the next update). I have no clue how to fix this, i tried placing _listTodos() everywhere to see if it executes before the widgets but there wasn't any improvement. The issue is in the ListDisplay class I think, so you can just skip over the rest, I just have the entire code for convenience.
import 'package:flutter/material.dart';
import 'model/todo_model.dart';
import 'model/todo.dart';
class ListGradesPage extends StatefulWidget {
final String title;
ListGradesPage({this.title, Key key}) : super(key: key);
_ListGradesPageState createState() => _ListGradesPageState();
}
var _todoItem;
var _lastInsertedId = 0;
final _model = TodoModel();
Future<void> _deleteTodo() async {
_model.deleteAllTodo();
}
class _ListGradesPageState extends State<ListGradesPage> {
//final _model = TodoModel();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
actions: <Widget>[
IconButton(
icon: Icon(Icons.edit),
onPressed: () {
print('editing...');
//_listTodos();
}),
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
print('deleting all...');
setState(() {
_deleteTodo();
});
}),
],
),
body: ListDisplayPage(),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AddGrade()),
);
},
child: Icon(Icons.add),
backgroundColor: Colors.blue,
),
);
}
}
class ListDisplayPage extends StatefulWidget {
ListDisplay createState() => ListDisplay();
}
class ListDisplay extends State<ListDisplayPage> {
int _selectedIndex;
List<Todo> todos = new List<Todo>();
Future<void> _listTodos() async {
todos = await _model.getAllTodos();
if (todos.isEmpty) {
print('it is empty-2.');
} else {
print("not empty-2");
}
print('To Dos:');
for (Todo todo in todos) {
print(todo);
}
}
_onSelected(int index) {
_selectedIndex = index;
}
@override
void initState() {
super.initState();
_listTodos();
// _listTodos() is not calling the function above for some reason, but executes everything below it
// In the database there are items stored however it says the databse is empty...
// until i add a new item and everything shows up except the item i recently added
if (todos.isEmpty) {
print('To Dos:');
for (Todo todo in todos) {
print(todo);
}
print('it is empty.');
} else {
print("not empty");
}
}
@override
Widget build(BuildContext context) {
//Color clr = Colors.transparent;
return todos.isEmpty
? Center(
child: Text(
'Nothing to show! Is it empty? ' + (todos.isEmpty).toString()))
: ListView.builder(
itemCount: todos.length,
itemBuilder: (context, index) {
return Card(
// <-- Card widget
child: Container(
color: _selectedIndex != null && _selectedIndex == index
? Colors.lightBlueAccent
: Colors.transparent,
child: ListTile(
leading: GestureDetector(
onTap: () {
setState(() {
_onSelected(index);
print(index);
});
},
child: Container(
width: MediaQuery.of(context).size.width / 2,
child:
Text(todos[index].sid + '\n' + todos[index].grade),
),
),
),
),
);
},
);
}
}
class AddGrade extends StatelessWidget {
String _sid, _grade;
final _formKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Add Grade"),
),
body: Form(
key: _formKey,
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(15.0),
child: TextFormField(
decoration: const InputDecoration(
hintText: 'Student ID',
labelText: 'SID',
),
onSaved: (String value) {
print('Saving SID $value');
_sid = value.toString();
},
),
),
Padding(
padding: const EdgeInsets.all(15.0),
child: TextFormField(
decoration: const InputDecoration(
hintText: 'Student Grade',
labelText: 'Grade',
),
onSaved: (String value) {
print('Saving Grade $value');
_grade = value.toString();
},
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
_formKey.currentState.save();
_addTodo();
//_listTodos();
Navigator.pop(context);
},
child: Icon(Icons.save),
backgroundColor: Colors.blue,
),
);
}
Future<void> _addTodo() async {
Todo newTodo = Todo(sid: _sid, grade: _grade);
_lastInsertedId = await _model.insertTodo(newTodo);
}
}
Console Output (on execution):
Restarted application in 1,607ms.
I/flutter (14196): To Dos:
I/flutter (14196): it is empty.
I/flutter (14196): not empty-2
I/flutter (14196): To Dos:
I/flutter (14196): Todo{id: 1, sid: q, grade: qq}
I/flutter (14196): Todo{id: 2, sid: w, grade: ww}
I/flutter (14196): Todo{id: 3, sid: e, grade: ee}
I/flutter (14196): Todo{id: 4, sid: r, grade: }
I/flutter (14196): Todo{id: 5, sid: hh, grade: kk}
Screenshots of emulator, before adding new student, and after adding new student (the recent one doesn't show up either until I add another student again),
I apologize if i didn't follow the guidelines, never really posted questions on here before.
Upvotes: 0
Views: 714
Reputation: 752
Are you aware of FutureBuilder? I would suggest wrapping your ListView.builder
in a future builder and passing in the _loadTodos
function as the future. Then you can remove all of the initState code that initializes the todos.
Generally, I find that doing async work in initState
doesn't always work. The UI has already built, and doesn't know to rebuild when the async work is complete. Another option might just be to call setState
once the async function completes with the todos. I would think that the FutureBuilder is the better way to do it though.
If you need some additional help, let me know. I could probably write some of it out for you.
Upvotes: 1