How to show seperate DataTables and Text for each map in json list?

Viewed 196

I want to show json data with DataTable() but i get error:

type '(dynamic) => Column?' is not a subtype of type '(dynamic) => DataTable' of 'f'

My question is how i can resolve the error but most importantly how can i iterate through the list block_data and then for each map show header and title in seperate DataTable() where they are on top of eachother and eachdescription below each DataTable()?

This is the view where i call the method setTestData() which awaits the Future AppContent().getAppContent() and then set the data to the field testObject and i also initialize setTestData() in current state. I can then use testObject to acces the json data.

My goal is to show EACH map from list block_data as SEPERATE DataTable for my usecase i have to do that. The reason why i want to this like that is because i also want to show the description below DataTable as a seperate Text() widget because it can be too long and in my usecase it has to be below the table

I now have this AppView statefull widget which i want to use to show each DataTable() seperatly based on each map from list block_data. I am not sure if i do it the right way but right now i get the error so it is more unclear if i can even achieve my goal this way:

class AppView extends StatefulWidget {
  const AppView({Key? key}) : super(key: key);

  @override
  _AppViewState createState() => _AppViewState();
}

class _AppViewState extends State<AppView> {
  final _scaffoldKey = GlobalKey<ScaffoldState>();
  late Map<String, dynamic> testObject = {};

  setTestData() async {
    await AppContent()
        .getAppContent()
        .then((result) => setState(() => testObject = result));
  }

  @override
  void initState() {
    setTestData();
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        key: _scaffoldKey,
        body: CustomScrollView(
          slivers: <Widget>[
            SliverAppBar(
              leading: IconButton(
                icon: const Icon(Icons.menu,
                    size: 40), // change this size and style
                onPressed: () => _scaffoldKey.currentState?.openDrawer(),
              ),
            ),
            SliverList(
              delegate: SliverChildBuilderDelegate((context, index) {
                return Column(
                  children: [
                    FutureBuilder(
                        future: AppContent().getAppContent(),
                        builder: (context, snapshot) {
                          if (snapshot.hasData) {
                            debugPrint(testObject["data"]["views"]["books"][0]
                                    ["block_data"]
                                .toString());
                            return Column(
                              children: [
                                Container(
                                    alignment: Alignment.topLeft,
                                    child: (testObject["data"]["views"]["books"]
                                            [0]["block_data"])
                                        .map<DataTable>((object) {
                                      if (object.containsKey("header")) {
                                        return Column(
                                          children: [
                                            DataTable(
                                              horizontalMargin: 0,
                                              columnSpacing: 75,
                                              columns: <DataColumn>[
                                                DataColumn(
                                                  label: Container(
                                                      padding: EdgeInsets.zero,
                                                      child: Text(
                                                        object["header"]
                                                            .toString(),
                                                      )),
                                                ),
                                              ],
                                              rows: <DataRow>[
                                                DataRow(
                                                  cells: <DataCell>[
                                                    DataCell(Text(
                                                      object['title']
                                                          .toString(),
                                                    DataCell(Text(object['date'].toString()
                                                    ))
                                                  ],
                                                ),
                                              ],
                                            ),
                                            Text(object["description"]
                                                .toString())
                                          ],
                                        );
                                      } else {
                                        Container();
                                      }
                                    }).toList()),
                                Text(
                                    "This is another placeholder for another list")
                              ],
                            );
                          } else {
                            return CircularProgressIndicator();
                          }
                        }),
                  ],
                );
              }, childCount: 1),
            ),
          ],
        ),
      ),
    );
  }
}

This is the method AppContent().getAppContent() which grabs the json:

class AppContent {
  Future<Map<String, dynamic>> getAppContent() async {
    String jsonData = await rootBundle.loadString('assets/test.json');
    Map<String, dynamic> data = jsonDecode(jsonData);
    return data;
  }


}

And this the json which i call:

{
  "data": {


    "views": {
      "books": [

        {
          "block_type": "list",
          "block_data": [
            {
              "header": "FAQ",
              "long_text_type": "description",
              "title": "Service fees",
              "date": "19-01-2022",
              "description": "Information about fees and surcharges."

            },
            {
              "header": "FAQ",
              "long_text_type": "description",
              "title": "Returns & Refunds",
              "date": "03-06-2022",
              "description": "How to return products and recieve refunds.."

            }

          ]
    }
  }
}
}

Edit

I want it to look like the picture below where i have a datable for and description below that. But i want it for each map in list block_data and so i want to show the next map below the description and then show basicly DataTable -> description -> DataTable -> description. But i want to iterate through list block_data and generate DataTable and Text based on maps inside list which could be more than just two maps

enter image description here

1 Answers

There are multiple issues here.

  1. Your JSON has an error (probably a copy/paste error, but double-check it).
    Instead of
    "block_data": "block_data": [ you should have "block_data": [.
    Moreover, a bracket is missing at the end of your JSON file (but again, I guess that it's because you only showed a part of your file to help us investigate your problem)

  2. The error you wrote in your question is related to your .map<DataTable>((object) {
    When using the .map, the Object you specify is the return type of your mapping. In your case you're returning a Column and not a DataTable.
    If you want to iterate on a list, and create a list of Widgets in return, you can use this instead: .map<Widget>((object) {

  3. Finally, and the most important point of this answer : you're having problems here because you're not converting your JSON file in a Dart Object you can easily manipulate.
    You can simply paste your JSON file on this website : https://javiercbk.github.io/json_to_dart/ and retrieve the code to add to your project.
    Then, you'll have a model with a fromJson and a toJson methods.
    Thanks to those methods, you'll be able to create Dart Objects from your JSON values, and thus to create your Widgets easily.

With this answer, you should be good to go. Add a comment if I need to add more details.

Related