I am making a search page in flutter. I have sucsessfully added the search bar, but now adding the corresponding list is becoming an issue. The data that the user searches is from a json file, so I have sucsessfully programmed converting the json file to the correct internal data type and have stuctured the code so that the list would be filled before the building of the page. However, this seems to be not working and and the page is building before the parsing of the json is complete. Any ideas on how top proceed would be much appreciated.
I have tried using init state and putting the json read fuction in the beginning of the build fuction. Neither of these have worked. I have considered createing the list in a previous page and passing it to the search page, but I would much rather have it done in the page itself.
Below is the code I have for the page as of now.
import 'dart:convert';
import 'package:dnd_app/Models/fighter.dart';
import 'package:dnd_app/Models/monster.dart';
import 'package:flutter/material.dart';
import 'package:dnd_app/constants.dart' as constants;
import 'package:flutter/rendering.dart';
import 'package:flutter/services.dart';
import 'package:dnd_app/Models/pc.dart';
import 'package:flutter_svg/svg.dart';
class monsterSearch extends StatefulWidget {
const monsterSearch({super.key});
@override
State<monsterSearch> createState() => _monsterSearchState();
}
class _monsterSearchState extends State<monsterSearch> {
List<Monster> monsters = [];
int mom = 10;
@override
void initState() {
readJson();
super.initState();
}
@override
Widget build(BuildContext context) {
print(monsters.length);
return Scaffold(
appBar: constants.titleBar("Monster Search"),
backgroundColor: constants.greyGold(),
body: Column(
children: [
searchBar(),
Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: monsters.length,
itemBuilder: (context, index) {
return Text(monsters[index].name);
},
))
],
),
);
}
Future<void> readJson() async {
final String responce =
await rootBundle.loadString('assets/5e-SRD-Monsters.json');
final retData = jsonDecode(responce);
for (var mon in retData) {
try {
String sSpeed = mon["speed"];
sSpeed = sSpeed.substring(0, sSpeed.indexOf(' '));
monsters.add(Monster(
mon["name"],
mon["hit_points"],
mon["armor_class"],
mon["strength"],
mon["constitution"],
mon["dexterity"],
mon["intelligence"],
mon["wisdom"],
mon["charisma"],
int.parse(sSpeed)));
} on Error catch (_) {
continue;
} on Exception catch (_) {
continue;
}
}
print(monsters.length);
}
void waitingGame() async {
await readJson();
}
Container searchBar() {
return Container(
margin: EdgeInsets.only(top: 40, left: 20, right: 20),
decoration: BoxDecoration(
boxShadow: [BoxShadow(color: Colors.grey.withOpacity(0.11))]),
child: TextField(
decoration: InputDecoration(
filled: true,
fillColor: Colors.white,
hintText: 'Search Monster',
contentPadding: EdgeInsets.all(15),
prefixIcon: Padding(
padding: const EdgeInsets.all(12),
child: SvgPicture.asset('assets/pictures/icons8-search.svg'),
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(15),
borderSide: BorderSide.none)),
),
);
}
}
2
Answers
Have you tried to wrap
inside a FutureBuilder where the future will be your readJson.
Would look something like this:
Your readJson should return
Future<List<Monsters>>
so the FutureBuilder knows when data is existing. Your "old" Monster list can stay in case you need it somewhere elseThe issue you’re facing is that the page is building before the parsing of the JSON is complete. To solve this problem, we can use the
FutureBuilder
widget to handle asynchronous operations and wait for the JSON parsing to complete before building the page. Here’s how you can modify your code:ListView.builder
with a FutureBuilder widget and provide the readJson function as the future parameter.setState
after adding the Monsters to trigger a rebuild of the widget tree.With these changes, the
FutureBuilder
will wait for thereadJson
function to complete before building theListView
. While the JSON parsing is in progress, a loading indicator will be shown. If an error occurs during parsing, an error message will be displayed. Once the parsing is complete, theListView
will be built with the parsed data.Hope this helps your problem!