Shoji Yamada
Shoji Yamada

Reputation: 75

Dynamic List in Flutter using SharedPreferences

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.

Main Screen

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

Second Screen

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

Answers (3)

gbaccetta
gbaccetta

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

Tasnuva Tavasum oshin
Tasnuva Tavasum oshin

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

Aiman_Irfan
Aiman_Irfan

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

Related Questions