how to convert csv data from filepicker to dynamic list?

Viewed 312

I create apps that user can load csv file and i want csv data put into map so that i can make delete function or anything else.... Can somebody help me because i been searching for this it show how to convert csv using loadasset bundle i want to do it with pick file from phone storage

example: convert data from a csv to a dynamic List (Flutter)

I/flutter ( 4028): [[No,  Name,  Code], [1,  Ali,  A123], [2,  Abu,  B456], [3,  Amir,  C789], [4,  Safe,  D098], [5,  Alif,  E765 ]]

here my code

Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          title: Text("CSV DATA"),
          backgroundColor: Colors.redAccent[400],
        ),
        body: Container(
            child: SingleChildScrollView(
          child: Column(children: <Widget>[
            FutureBuilder(
              future: loadingCsvData(path),
              builder: (context, AsyncSnapshot<List<dynamic>> snapshot) {
                print(snapshot.data.toString());
                return snapshot.hasData
                    ? ListView(
                        scrollDirection: Axis.vertical,
                        shrinkWrap: true,
                        children: snapshot.data.map((data) {
                          return Visibility(
                              visible: visibilityController,
                              child: //Your card
                                  Card(
                                child: GestureDetector(
                                  onTap: () {
                                    withInputField(context);
                                    controller.text = data[1];
                                    _controller.text = data[2];
                                    setState(() {});
                                  },
                                  child: ListTile(
                                    title: Text(
                                      data[1].toString(),
                                      style: TextStyle(
                                          fontWeight: FontWeight.bold),
                                    ),
                                    subtitle: Text(data[2].toString()),
                                    isThreeLine: true,
                                    trailing: IconButton(
                                      icon: Icon(Icons.delete),
                                      onPressed: () {},
                                    ),
                                  ),
                                ),
                              ));
                        }).toList(),
                      )
                    : Center(
                        child: CircularProgressIndicator(),
                      );
              },
            ),
          ]),
        )),

This my function for file picker

Future<List<List<dynamic>>> loadingCsvData(String path) async {
    final csvFile = new File(path).openRead();
    return await csvFile
        .transform(utf8.decoder)
        .transform(
          CsvToListConverter(),
        )
        .toList();
  }

EDIT

my fetch data

FutureBuilder(
              future: loadingCsvData(path),
              builder: (context,
                  AsyncSnapshot<Map<int, Map<String, dynamic>>> snapshot) {
                print(snapshot.data.toString());
                return snapshot.hasData
                    ? ListView(
                        scrollDirection: Axis.vertical,
                        shrinkWrap: true,
                        children: [
                          Card(
                            child: ListTile(
                              title: Text(userList.toString()),
                            ),
                          )
                        ],
                      )
                    : Center(
                        child: CircularProgressIndicator(),
                      );
              },
            ),

is it right to do like this

1 Answers

I would create a model for the object you want to read.

Whithin the model I would prepare some functions to convert a single of your Row in a Map<String, dynamic> and to convert a List of Rows in a Map<int, Map<String, dynamic>>.

Here's an example:

//I suppose your single row element to be an User
class User {
  
  User({
    No,
    Name,
    Code,
  }) {
    this.No = No;
    this.Name = Name;
    this.Code = Code;
  }

  //Parameters
  int? No;
  String? Name;
  String? Code;

  // A map with an String key and dynamic value
  static Map<String, dynamic> userToMap(List<dynamic> row) {
    return {
      if (row[0] != null) 'No': row[0] as int,
      if (row[1] != null) 'Name': row[1] as String,
      if (row[2] != null) 'Code': row[2] as String
    };
  }

  // A map with an int key and Map<String, dynamic> value
  static Map<int, Map<String, dynamic>> userListToMap(
      List<List<dynamic>> userList) {
    userList.removeAt(0); //If you want to remove the first row containing the headers
    return userList.map((user) => userToMap(user)).toList().asMap();
  }
}

Then you could take the List<List<dynamic>> returned from your method loadingCsvData and call userListToMap.

UPDATE: After writing my answer I noticed that you don't actually need the class I built, you could take the functions userToMap and userListToMap alone and it should work.

EDIT:

You could change your loadingCsvData to look like this:

  Future<Map<int, Map<String, dynamic>>> loadingCsvData(String path) async {
    final csvFile = new File(path).openRead();
    return userListToMap(await csvFile
        .transform(utf8.decoder)
        .transform(
      CsvToListConverter(),
    ).toList());
  }
Related