Flutter DataTable Layout

Issue

I’ve got some layout trouble with DataTable in Flutter with a FutureBuilder, I’ve called the API and naturally it will display it like this:

enter image description here

Understandable, since I’m building a list of tables it will return multiple tables back. I want to map out only the Rows as a List and the columns should stay the same, exactly like this:

enter image description here

So, the columns First Name, Last Name and Delete are always the same, it just maps out the table row cells like in the second picture above.

Is this possible to achieve this with a DataTable using the FutureBuilder like in my example?

I’ve tried using the future builder in a DataRow cell since every child of the DataCell is a Widget, but it looks really horrible and I’m not sure it is the right practice…

Here is the code:

The API call:

import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'models/names.dart';

Future<List<NameData>> fetchNames() async {
  List<NameData> names = List();
  final response = await http.get('https://jsonplaceholder.typicode.com/posts');

  if (response.statusCode == 200) {
    // If the server did return a 200 OK response,
    // then parse the JSON.
    var namesJson = jsonDecode(response.body);
    print(response.body);
    for (int i = 0; i < namesJson.length; i++) {
      names.add(NameData.fromJson(jsonDecode(response.body)[i]));
    }
    return names;
  } else {
    // If the server did not return a 200 OK response,
    // then throw an exception.
    throw Exception('Failed to load names');
  }
}

The Names model:

import 'package:flutter/foundation.dart';
import 'dart:core';

class NameData extends ChangeNotifier {
  final int id;
  final int userId;
  final String title;
  final String body;

  NameData({
    this.id,
    this.userId,
    this.title,
    this.body,
  });

  factory NameData.fromJson(Map<String, dynamic> json) {
    return NameData(
      id: json["id"],
      userId: json["userId"],
      title: json["title"],
      body: json["body"],
    );
  }
}

And the Names List with the Data table:

import 'package:flutter/material.dart';
import 'models/names.dart';
import 'services/name_api.dart';

class NameList extends StatefulWidget {
  @override
  _NameList createState() => _NameList();
}

class _NameList extends State<NameList> {
  Future<List<NameData>> futureNames;

  @override
  void initState() {
    super.initState();
    futureNames = fetchNames();
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        SizedBox(
          height: 600,
          child: FutureBuilder<List<NameData>>(
            future: futureNames,
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return ListView.builder(
                  itemCount: snapshot.data.length,
                  itemBuilder: (context, index) {
                    return Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      mainAxisAlignment: MainAxisAlignment.spaceAround,
                      children: [
                        SizedBox(
                          height: 12.0,
                        ),
                        Container(
                          decoration: BoxDecoration(
                            color: Colors.grey[300],
                            borderRadius: BorderRadius.all(
                              Radius.circular(12.0),
                            ),
                          ),
                          child: SingleChildScrollView(
                            scrollDirection: Axis.horizontal,
                            child: DataTable(
                              columns: <DataColumn>[
                                DataColumn(
                                  label: Text(
                                    'First Name',
                                    style:
                                        TextStyle(fontStyle: FontStyle.italic),
                                  ),
                                ),
                                DataColumn(
                                  label: Text(
                                    'Last Name',
                                    style:
                                        TextStyle(fontStyle: FontStyle.italic),
                                  ),
                                ),
                                DataColumn(
                                  label: Text(
                                    'Delete',
                                    style:
                                        TextStyle(fontStyle: FontStyle.italic),
                                  ),
                                ),
                              ],
                              rows: <DataRow>[
                                DataRow(
                                  cells: <DataCell>[
                                    DataCell(
                                        Text('${snapshot.data[index].id}')),
                                    DataCell(
                                        Text('${snapshot.data[index].userId}')),
                                    DataCell(Icon(Icons.delete)),
                                  ],
                                ),
                              ],
                            ),
                          ),
                        ),
                        SizedBox(
                          height: 16.0,
                        ),
                      ],
                    );
                  },
                );
              } else if (snapshot.hasError) {
                return Text("${snapshot.error}");
              }
              return Container();
            },
          ),
        ),
      ],
    );
  }
}

Thank you in advance for your time and help.

Solution

Step 1:

 Future<List<NameData>> generateList() async {
    final response =
        await http.get('https://jsonplaceholder.typicode.com/posts');

    var list = await json.decode(response.body).cast<Map<String, dynamic>>();
    return await list.map<NameData>((json) => NameData.fromJson(json)).toList();
  }

Step 2:

@override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        appBar: AppBar(
          title: Text('DataTable'),
        ),
        body: Container(
            child: FutureBuilder<List<NameData>>(
          future: generateList(),
          builder: (context, snapShot) {
            if (snapShot.hasData) {
              return SingleChildScrollView(
                scrollDirection: Axis.horizontal,
                child: DataTable(
                  columns: <DataColumn>[
                    DataColumn(
                      label: Text(
                        'First Name',
                        style: TextStyle(fontStyle: FontStyle.italic),
                      ),
                    ),
                    DataColumn(
                      label: Text(
                        'Last Name',
                        style: TextStyle(fontStyle: FontStyle.italic),
                      ),
                    ),
                    DataColumn(
                      label: Text(
                        'Delete',
                        style: TextStyle(fontStyle: FontStyle.italic),
                      ),
                    ),
                  ],
                  rows: snapShot.data.map<DataRow>((e) {
                    return DataRow(
                      cells: <DataCell>[
                        DataCell(Text('${e.id}')),
                        DataCell(Text('${e.userId}')),
                        DataCell(Icon(Icons.delete)),
                      ],
                    );
                  }).toList(),
                ),
              );
            }else{
              return CircularProgressIndicator();
            }
          },
        )),
      ),
    );
  }

DataTable

Answered By – Balasubramani Sundaram

Answer Checked By – Gilberto Lyons (FlutterFixes Admin)

Leave a Reply

Your email address will not be published. Required fields are marked *