mycotoad
mycotoad

Reputation: 1

Why is snapshot.data empty when using FutureBuilder with PaginatedDataTable in Flutter 3.10 for Web?

Flutter 3.10: FutureBuilder with PaginatedDataTable from GET Response, but snapshot.data is Empty.

I am creating an app which include a User List page showing records in a PaginatedDataTable inside a FutureBuilder. The PaginatedDataTable includes a DataTableSource, which relies upon a GET request/response which returns a List/, where User refers to a model.

EDITED: Replaced original code samples below. Revised to consolidate into single file for debugging, and included more print statements to assist with debugging through console.

PROBLEM from Console:

{alias: ALIAS, password: password}

AsyncSnapshot<List>(ConnectionState.waiting, null, null, null) null snapshot.hasData failed

200 [{"id":6,"alias":"username","name_first":"fIrStNaMe","name_last":"lAsTnAmE","email":"[email protected]","phone":"2222222222","date_birth":"2000-12-01"},{"id":1,"alias":"ALIAS","name_first":"FiRsTnAmE","name_last":"LaStNaMe","email":"[email protected]","phone":"9999999999","date_birth":"2000-01-31"}]

user_fetch: after response received [{id: 6, alias: username, name_first: fIrStNaMe, name_last: lAsTnAmE, email: [email protected], phone: 2222222222, date_birth: 2000-12-01}, {id: 1, alias: ALIAS, name_first: FiRsTnAmE, name_last: LaStNaMe, email: [email protected], phone: 9999999999, date_birth: 2000-01-31}]

user_fetch, 200 response received, before return list [{id: 6, alias: username, name_first: fIrStNaMe, name_last: lAsTnAmE, email: [email protected], phone: 2222222222, date_birth: 2000-12-01}, {id: 1, alias: ALIAS, name_first: FiRsTnAmE, name_last: LaStNaMe, email: [email protected], phone: 9999999999, date_birth: 2000-01-31}]

AsyncSnapshot<List>(ConnectionState.done, null, Expected a value of type 'FutureOr<List>', but got one of type 'List', ) null snapshot.hasData failed

CODE BELOW:

import 'dart:convert';
import 'package:flutter_axum/providers/url.dart';
import 'package:flutter/material.dart';
import 'package:flutter_axum/providers/user_auth.dart';
//import 'package:flutter_axum/providers/user_data_table_source.dart';
//import 'package:flutter_axum/providers/user_fetch.dart';
//import 'package:flutter_axum/widgets/paginated_data_table.dart';
import 'package:http/http.dart' as http;
import '../models/user.dart';
import '../providers/user_secure_storage.dart';

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  //final DataTableSource source = UserDataTableSource();
  //final columns = UserDataTableSource().getColumns();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('User Paginated Data Table'),
        actions: [
          IconButton(
              icon: const Icon(Icons.exit_to_app),
              onPressed: () {
                ///logout
                AuthenticationProvider().logoutUser(context: context);
              }),
        ],
      ),
        body: FutureBuilder(
          future: getUsers(),
          builder: (context, snapshot) {
            print(snapshot);
            print(snapshot.data);
            if (ConnectionState.active != null && !snapshot.hasData) {
              print("snapshot.hasData failed");
              return Center(child: Text('Loading'));
            }
            if (ConnectionState.done != null && snapshot.hasError) {
              print("snapshot.hasError failed");
              return Center(child: Text(snapshot.error.toString()));
            } else {
              print("snapshot reaches PaginatedDataTable");
              return PaginatedDataTable(
                  columns: getColumns(),
                  source: UserDataTableSource(source: snapshot.data! as List<User>)
              );
            }
          }
        )
    );
  }
}

Future<List<User>> getUsers() async {

  final StorageService storageService = StorageService();
  final bearer = await storageService.readSecureData('token');
  final url = BaseUrl.baseUrl;
  String _url = "$url/user/list";

  try {
    final request = await http.get(Uri.parse(_url), headers: {'Access-Control-Allow-Origin': '*', 'Authorization': 'Bearer $bearer'});

    print(request.statusCode);
    print(request.body);

    if (request.statusCode == 200 || request.statusCode == 201){

      final list = json.decode(request.body);
      print("user_fetch: after response received");
      print(list);

      if (json.decode(request.body) == null) {
        return list;
      } else {

        print("user_fetch, 200 response received, before return list");
        print(list);

        return list;
      }
    } else {
      List<User> list = [];
      return list;
    }
  } catch (e) {
    return Future.error(e.toString());
  }
}

class UserDataTableSource extends DataTableSource {
  UserDataTableSource({required source}) : userList = source;

  final List<User> userList;

  @override
  DataRow getRow(int index) {
    final User user = userList[index];

    return DataRow.byIndex(index: index, cells: [
      DataCell(Text('${user.id}')),
      DataCell(Text(user.alias)),
      DataCell(Text(user.nameFirst)),
      DataCell(Text(user.nameLast)),
      DataCell(Text(user.email)),
      DataCell(Text(user.phone)),
      DataCell(Text(user.dateBirth)),
      //const DataCell(Text("Edit|Delete")),
    ]);
  }
    @override
    bool get isRowCountApproximate => false;
    @override
    int get rowCount => userList.length;
    @override
    int get selectedRowCount => 0;
}

const String colID = 'ID';
const String colAlias = 'Alias';
const String colNameFirst = 'First Name';
const String colNameLast = 'Last Name';
const String colEmail = 'Email';
const String colPhone = 'Phone';
const String colDateBirth = 'Date of Birth';

List<DataColumn> getColumns(){
  final List<DataColumn> columns =
  <DataColumn>[
    const DataColumn(
      label: Text(colID),
      tooltip: colID,
    ),
    const DataColumn(
      label: Text(colAlias),
      tooltip: colAlias,
    ),
    const DataColumn(
      label: Text(colNameFirst),
      tooltip: colNameFirst,
    ),
    const DataColumn(
      label: Text(colNameLast),
      tooltip: colNameLast,
    ),
    const DataColumn(
      label: Text(colEmail),
      tooltip: colEmail,
    ),
    const DataColumn(
      label: Text(colPhone),
      tooltip: colPhone,
    ),
    const DataColumn(
      label: Text(colDateBirth),
      tooltip: colDateBirth,
    ),
  ];

  return columns;
}

In the PROBLEM output above, you can see the print statements return the Response Status Code, followed by the response.body, then a print of the list following json.decode.

The output shows the NULL snapshot while ConnectionState is 'waiting', but then it returns empty with an error message, "Expected a value of type 'FutureOr<List>', but got one of type 'List'" once ConnectionState returns 'done'.

Any feedback or guidance would be greatly appreciated!

Upvotes: 0

Views: 111

Answers (0)

Related Questions