Reputation: 427
I'm using a JSON file to store a list that I want to display and update. I have one StatefulWidget(called "HOME") that shows the list using a ListView.builder. I also have a StatefulWidget(called "ADD") that adds an object to the list and updates the JSON file. When I finish adding the list a Navigate back to "HOME", I receive this error:
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
PlayerList playerList;
@override
void initState() {
super.initState();
readPlayerData().then((PlayerList list) {
playerList = list;
});
}
@override
Widget build(BuildContext context) {
// add Player to the PlayerList
void addPlayer() async {
await Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => AddPlayer()),
);
initState();
}
void removePlayer(int index) async {
playerList.players.removeAt(index);
await writePlayerData(playerList);
}
playerList = ModalRoute.of(context).settings.arguments;
return Scaffold(
backgroundColor: Colors.grey[900],
appBar: AppBar(
title: Text('Smash Tracker'),
centerTitle: true,
backgroundColor: Colors.grey[850],
elevation: 0,
),
floatingActionButton: FloatingActionButton(
onPressed: () async {addPlayer();},
child: Icon(Icons.add),
backgroundColor: Colors.grey[600],
),
body: Padding(
padding: EdgeInsets.all(15.0),
child: Container(
child: Card(
color: Colors.grey[900],
shadowColor: Colors.black87,
child: ListView.builder(
itemCount: playerList.players.length,
itemBuilder: (context, index) {
return ListTile(
//leading: characterIcons(playerList.players[index]),
title: Text(
playerList.players[index].playerId,
style: TextStyle(
color: Colors.amberAccent,
),
),
subtitle: Text(
playerList.players[index].playerSetCount,
style: TextStyle(
color: Colors.amberAccent,
),
),
onTap: () {
Navigator.pushNamed(context, '/playerCard', arguments: {
'player': playerList.players[index],
'playerList': playerList,
'index': index
});
},
trailing: IconButton(
onPressed: () async {
removePlayer(index);
PlayerList newPlayerList = await readPlayerData();
setState(() {
playerList = newPlayerList;
});
},
icon: Icon(Icons.delete_outline),
color: Colors.white,
),
);
},
),
),
),
),
);
}
}
The code used to save a new Object when the 'Save' button is pressed
ADD:
void _saveForm() async {
PlayerList playerList = await readPlayerData();
Player newPlayer = new Player("${playerName.trim()}", "0 - 0",
new Characters(_myChar1Result, _myChar2Result), "");
playerList.players.add(newPlayer);
await writePlayerData(playerList);
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => Home()),
);
}
I think the error occurs when the ListView.builder attemps to call on the playerList object. I'm not sure. I'll be happy to provide any additional information.
'Edit:'Here is the readPlayerData() including the methods it relies on:
Future<PlayerList> readPlayerData () async {
try {
final file = await _localFile;
String contents = await file.readAsString();
final jsonResponse = (jsonDecode(contents)); //wrap in encode
PlayerList playerList = PlayerList.fromJson(jsonResponse);
return playerList;
} catch (e) {
print(e);
return getPlayerList(); //just loads a placeholder json in the assets folder;
}
Future<String> get _localPath async {
final directory = await getApplicationDocumentsDirectory();
return directory.path;
}
Future<File> get _localFile async {
final path = await _localPath;
print(path);
return File('$path/playerData.json');
}
The json file saves the way I want it to.
Upvotes: 2
Views: 336
Reputation: 8978
There were multiple problems in your code, and this is how I fixed it.
SOLUTION I will give you the solution file wise, so follow along
1. HOME
addPlayer()
and removePlayer()
setState((){})
for playerList
in initState()
playerList = ModalRoute.of(context).settings.arguments;
. Too buggy to use to this lineNavigator.pushAndRemoveUntil()
in addPlayer()
class _HomeState extends State<Home> {
PlayerList playerList;
@override
void initState() {
super.initState();
readPlayerData().then((PlayerList list) {
setState(() => playerList = list);
});
}
// add Player to the PlayerList
void addPlayer() async {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => AddPlayer()),
(_) => false);
//initState();
}
void removePlayer(int index) async {
playerList.players.removeAt(index);
await writePlayerData(playerList);
}
@override
Widget build(BuildContext context) {
// copy paste your Scaffold content here
// rest everything will be same
// NO layerList = ModalRoute.of(context).settings.arguments;
return Scaffold();
}
}
2. ADD
import 'package:smash_tracker/models/character_model.dart' as Characters;
new Characters.Characters(_myChar1Result, _myChar2Result)
Navigator.pushAndReplaceUntil()
PlayerList playerList = ModalRoute.of(context).settings.arguments;
import 'package:smash_tracker/models/character_model.dart' as Characters;
void _saveForm() async {
setState(() {
_myChar1Result = _myChar1;
_myChar2Result = _myChar2;
});
PlayerList playerList = await readPlayerData();
Player newPlayer = new Player("${playerName.trim()}", "0 - 0",
new Characters.Characters(_myChar1Result, _myChar2Result), "");
playerList.players.add(newPlayer);
print('added new Player');
await writePlayerData(playerList);
print('updated JSON');
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => Home())
(_) => false);
}
@override
Widget build(BuildContext context) {
// no more PlayerList playerList = ModalRoute.of(context).settings.arguments;
return Scaffold();
}
After testing the app, it works like the below.
Upvotes: 2