2

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.

3 Answers 3

3

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']!),
      ),
    );
  }
}
Sign up to request clarification or add additional context in comments.

5 Comments

The second problem is solved, thank you ! For the first problem, I don't know where to put the json in the code.
Ok @ShojiYamada I modified your code with my suggestion of using jsonEncode / Decode. I did not test the code, so some more tweaking coud be needed
also I did not really test it and added some non null assertion to go fast trough it... So make sure that is pertinent to your useCase
Hello sir, I tried applying the code but it throws an error when I click the Add To Cart button. The dubug console says that: Unhandled Exception: NoSuchMethodError: The method 'add' was called on null. I tried searching for solution but I can't find any. I've been experimenting different stuff but it does not work. (I guess that the error comes from the saveData function).
As I told you I did really not test the code. The error come from the fact that for the first item the list in the shared preferences doesn't exist yet. You should check if the value received is null. I update the code
1

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

Comments

0

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
        };
      }
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.