I have build a drag and drop list with static data which work well, now when I try to add data from a webservice it doesn't show in the widget (it show only the static data) :
But at the same time when I do a print() of the list in the console it shows all the data (static and from the webservice):
Here is my code :
class Taches extends StatefulWidget{
@override
TachesState createState(){
return new TachesState();
}
}
class TachesState extends State<Taches> {
//the static data
List<String> listeTaches = [
'Tâche 1',
'Tâche 2',
'Tâche 3',
'Tâche 4',
'Tâche 5',
'Tâche 6',
'Tâche 7',
'Tâche 8',
'Tâche 9',
'Tâche 10',
];
void getTaches() async {
Session session = new Session();
var taches = jsonDecode(await session.authentification());
//here I add the data from the webservice
for(int i = 0; i < taches['result']["inRangeTasks"].length ; i ){
var tacheStr = taches['result']["inRangeTasks"][i]['name'];
listeTaches.add(tacheStr.toString());
}
print(listeTaches);
}
_onReorder(oldIndex, newIndex) {
setState((){
if(newIndex > oldIndex){
newIndex -= 1;
}
var item = listeTaches.removeAt(oldIndex);
listeTaches.insert(newIndex, item);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: NavDrawer(),
appBar: AppBar(
title: Text('Beotic Project'),
centerTitle: true,
),
body: ReorderableListView(
header: Center(
child: Container(
child: Text(
'Listes des tâches',
style: Theme.of(context).textTheme.headline5,
),
padding: EdgeInsets.symmetric(vertical: 20)
)
),
children: listeTaches.map((e) => ListTile(
key: UniqueKey(),
leading: Icon(Icons.task),
title: Text(e),
trailing: Icon(Icons.more_vert),
)).toList(),
onReorder: _onReorder,
),
);
}
@override
void initState(){
//I directly call, in the initState function, the function which extract the data from the webservice and put it in the list
getTaches();
}
}
My goal is to make all the data from the list appear on the widget,
May be I'm doing something wrong,
Thanks for helping !
CodePudding user response:
The problem with your code is that although getTaches()
is an async
function, you can't await
it in initState
, because initState
can't be an async function. As a result your ReorderableListView
will be built earlier than the data is returned and added to listeTaches
in getTaches()
function.
The solution is using a FutureBuilder
, and building the widget only after the future (fetching) is completed. Check the following code. I simplified it and simulated a delay and the backend call, but you can see how it works and adjust it to your needs.
import 'package:flutter/material.dart';
void main() => runApp(
const MaterialApp(
home: Scaffold(body: Taches()),
),
);
class Taches extends StatefulWidget {
const Taches({Key? key}) : super(key: key);
@override
TachesState createState() => TachesState();
}
class TachesState extends State<Taches> {
//the static data
List<String> listeTaches = [
'Tâche 1',
'Tâche 2',
'Tâche 3',
'Tâche 4',
'Tâche 5',
'Tâche 6',
'Tâche 7',
'Tâche 8',
'Tâche 9',
'Tâche 10',
];
Future<List<String>> getTaches() async {
return Future.delayed(const Duration(milliseconds: 2000), () {
for (int i = 11; i <= 20; i ) {
listeTaches.add('Tâche $i');
}
return listeTaches;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: FutureBuilder<List<String>>(
future:
getTaches(), // a previously-obtained Future<String> or null
builder: (BuildContext context,
AsyncSnapshot<List<String>> snapshot) {
if (snapshot.hasError) {
// manage error
return const Text('Error');
}
// no error and we have data
if (snapshot.hasData) {
return ReorderableListView(
header: Center(
child: Text(
'Listes des tâches',
style: Theme.of(context).textTheme.headline5,
)),
children: listeTaches
.map((e) => ListTile(
key: UniqueKey(),
leading: const Icon(Icons.task),
title: Text(e),
trailing: const Icon(Icons.more_vert),
))
.toList(),
onReorder: (oldIndex, newIndex) => {},
);
}
// show initial data while loading
return const Center(child: CircularProgressIndicator());
})));
}
}