Search code examples
jsonflutterdartdatatable

flutter paginated data table with JSON api not working


in my flutter project I'm using an api to fetch users and display it on the table. and to do that i used paginated data table. but when i try to use it in future builder the source for the table is not being passed to data source. source: dataSource(snapshot.data)) and it underlines on snapshot.data and throws an error The argument type 'Object?' can't be assigned to the parameter type 'List<User>' i referred to a question in stackoverflow this was the answer given . so why is this thrown?

the code is similar to the question i mentioned.

this is api...

import 'package:http/http.dart' as http;
import '../user_model.dart';

Future<List> fetchUsers() async {
  Uri url = Uri.parse("https://jsonplaceholder.typicode.com/users");
  final response = await http.get(url);
  return usersFromJson(response.body);
}

this is the model...

import 'dart:convert';

List<User> usersFromJson(String str) =>
    List<User>.from(json.decode(str).map((json) => User.fromJson(json)));
String usersToJson(List<User> data) =>
    json.encode(List<dynamic>.from(data.map((e) => e.toJson())));

class User {
  int? id;
  String? name;
  String? username;
  String? email;
  String? role;
  String? password;

  User(
      {this.id,
      this.name,
      this.username,
      this.email,
      this.role,
      this.password});

  factory User.fromJson(Map<String, dynamic> json) => User(
      email: json['title'],
      name: json['title'],
      id: json['id'],
      username: json['title'],
      role: json['title']);

  Map<String, dynamic> toJson() => {
        "name": name,
        "username": username,
        "email": email,
        "role": role,
        "password": password
      };
}

this is the futurebuilder in the main.

FutureBuilder(
                        future: fetchUsers(),
                        builder: (context, snapshot) {
                          if (snapshot.hasData) {
                            return Column(
                              children: [
                                PaginatedDataTable(
                                    sortColumnIndex: sortColumnIndex,
                                    sortAscending: isAscending,
                                    columns: [
                                      DataColumn(
                                          label: const Text("Id"),
                                          onSort: onSort),
                                      DataColumn(
                                          label: const Text("Name"),
                                          onSort: onSort),
                                      DataColumn(
                                          label: const Text("Username"),
                                          onSort: onSort),
                                      DataColumn(
                                          label: const Text("Email"),
                                          onSort: onSort),
                                      DataColumn(
                                          label: const Text("Roles"),
                                          onSort: onSort),
                                      DataColumn(
                                          label: const Text("Actions"),
                                          onSort: onSort),
                                    ],
                                    header: Row(
                                      mainAxisAlignment:
                                          MainAxisAlignment.spaceBetween,
                                      children: [
                                        Text(
                                          "Manage Users",
                                          style: TextStyle(
                                              fontSize: width * 0.04,
                                              fontWeight: FontWeight.normal),
                                        ),
                                        MaterialButton(
                                          onPressed: () {
                                            showMaterialModalBottomSheet(
                                                context: context,
                                                builder: (context) => SizedBox(
                                                      height: height * 0.9,
                                                      child:
                                                          BottomSheetWidget(),
                                                    ),
                                                shape:
                                                    const RoundedRectangleBorder(
                                                        borderRadius:
                                                            BorderRadius.only(
                                                                topLeft: Radius
                                                                    .circular(
                                                                        15),
                                                                topRight: Radius
                                                                    .circular(
                                                                        15))));
                                          },
                                          color: const Color.fromRGBO(
                                              30, 119, 66, 1),
                                          shape: RoundedRectangleBorder(
                                              borderRadius:
                                                  BorderRadius.circular(10)),
                                          child: Text(
                                            "Add User",
                                            style: TextStyle(
                                                color: Colors.white,
                                                fontSize: width * 0.03),
                                          ),
                                        )
                                      ],
                                    ),
                                    source: dataSource(snapshot.data))
                              ],
                            );
                          } else if (snapshot.hasError) {
                            return Text("${snapshot.error}");
                          }
                          return const Center(child: CircularProgressIndicator());
                        })

i called the dataTable source as follows.

DataTableSource dataSource(List<User> userList) => MyTable(datasList: userList);

and finally dataTable source looks as follows

class MyTable extends DataTableSource {
  MyTable({required this.datasList});
  final List<User> datasList;
  
  @override
  DataRow? getRow(int index) {
    return DataRow.byIndex(index: index, cells: [
      DataCell(Text(datasList[index].id.toString())),
      DataCell(Text(datasList[index].name.toString())),
      DataCell(Text(datasList[index].username.toString())),
      DataCell(Text(datasList[index].email.toString())),
      DataCell(Text(datasList[index].role.toString())),
      const DataCell(Text("Edit|Delete")),
    ]);
  }

  @override
  bool get isRowCountApproximate => false;

  @override
  int get rowCount => datasList.length;

  @override
  int get selectedRowCount => 0;
}

Solution

  • Try to cast it as this:

    source: dataSource(snapshot.data! as List<User>))
    

    snapshot.data is an object because it can be for example a List, a Map and so on. But you know that it is not null and it is a List<User> so you can just cast it.