Reputation: 75
Hello, I'm trying to make an app where I can store data inputted by the user like this one. My task is to use SharedPreferences to store the data.
I used SharedPreferences to save the data in a List
saveData() async {
List<String> itemData = [];
itemData.add(fstcontroller.text);
itemData.add(sndcontroller.text);
itemData.add(trdcontroller.text);
itemData.add(fthcontroller.text);
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setStringList("item", itemData);
}
I have 2 problems, First Problem: whenever I click the Show Cart button, it shows this one
I don't want to display like this, I want to only display the "Item Brand", the rest will not be displayed. Then, if I click the cell, it will display the full details of the item in the third screen.
here's the SecondScreen
class SecondScreen extends StatefulWidget {
@override
State createState() => new DynamicList();
}
class DynamicList extends State<SecondScreen> {
List<String> listItems = [];
@override
void initState() {
super.initState();
getUser();
}
getUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
var itemData = prefs.getStringList("item");
setState(() {
listItems = itemData;
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
body: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: listItems.length, itemBuilder: buildList),
)
],
),
);
}
Widget buildList(BuildContext context, int index) {
return Container(
margin: EdgeInsets.all(4),
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
width: 2,
),
borderRadius: BorderRadius.circular(5)),
child: ListTile(
title: Text(listItems[index]),
),
);
}
}
Second problem: Whenever I add multiple data, the data doesn't stack. It only replaces the data.
Upvotes: 2
Views: 4511
Reputation: 4577
I think you need to rethink how you are storing and reading your data.
Right now you are storing a list of the four fields under the key "item", so each time you store your data you erase "item" by putting the 4 item fields in the list.
Although I'm not sure Shared preferences is the best way to go, you could do as follows: Put the fours fields as a json serialized and store each json string in your list.
For the second problem, When storing it you should first retrieve the existing list and update that list before storing it back.
var itemData = prefs.getStringList("item")
Than add the new item to the list:
itemData.add(newItem)
Store back the updated list
prefs.setStringList("item", itemData);
Now when you retrieve the list you retrieve your json string
To work with json
import 'dart:convert';
Then use jsonDecode(stringJson)
to get the kson back from your listItem in shared preferences and jsonEncode(jsonObject)
to encode your object to string before storing it.
For the first problem, once you have a json, you access a field like this:
jsonItem['brand']
Ps I was on my smartphone, I couldn't write full code for you. Maybe later
Edit: so now that I'm back home. For the json object to minimally modify your code (NOT TESTED):
saveData() async {
final Map<String, String> item = Map<String, String>();
item['brand'] = fstcontroller.text;
item['size'] = sndcontroller.text);
item['quantity'] = trdcontroller.text);
item['color'] = fthcontroller.text);
SharedPreferences prefs = await SharedPreferences.getInstance();
List<String> cart = prefs.getStringList("cart");
if (cart == null) cart = [];
cart.add(jsonEncode(item));
prefs.setStringList("cart", cart);
}
Then the code of your second screen become (again NOT TESTED - My changes are commented):
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
class SecondScreen extends StatefulWidget {
@override
State createState() => new DynamicList();
}
class DynamicList extends State<SecondScreen> {
// I changed the type of your list
List<Map<String, String>> listItems = [];
@override
void initState() {
super.initState();
getUser();
}
getUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
//I chaged these lines to retrieve the cart instead
final cart = prefs.getStringList("cart")!;
setState(() {
//convert the string cart List back to a list of objects:
cart.forEach((item) {
listItems.add(jsonDecode(item));
});
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
body: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: listItems.length, itemBuilder: buildList),
)
],
),
);
}
Widget buildList(BuildContext context, int index) {
return Container(
margin: EdgeInsets.all(4),
decoration: BoxDecoration(
border: Border.all(
color: Colors.black,
width: 2,
),
borderRadius: BorderRadius.circular(5)),
child: ListTile(
// Only use the 'brand' field as title of your list
title: Text(listItems[index]['brand']!),
),
);
}
}
Upvotes: 3
Reputation: 4740
Use Map to Store Value in Shared Preference Not List
.
SharedPreferences shared_User = await SharedPreferences.getInstance();
Map decode_options = jsonDecode(jsonString);
String user = jsonEncode(User.fromJson(decode_options));
shared_User.setString('user', user);
SharedPreferences shared_User = await SharedPreferences.getInstance();
Map userMap = jsonDecode(shared_User.getString('user'));
var user = User.fromJson(userMap);
class User {
final String name;
final String age;
User({this.name, this.age});
factory User.fromJson(Map<String, dynamic> parsedJson) {
return new User(
name: parsedJson['name'] ?? "",
age: parsedJson['age'] ?? "");
}
Map<String, dynamic> toJson() {
return {
"name": this.name,
"age": this.age
};
}
}
Upvotes: 0
Reputation: 375
For the first problem, your "Shared Preferences" safe all the data that you add into "item Data". You need to access the "item Data" to only select the brand by using the property name that you have save. For the second problem I still haven't figure it out yet
Upvotes: 1