table icon indicating copy to clipboard operation
table copied to clipboard

table-core throw errors when trying to call table table.getHeaderGroups()

Open trungvose opened this issue 2 years ago • 2 comments

Describe the bug

I am trying to use table-core in our application and there were a few hiccups.

Issues

1. Inconsistent between documentation and code

On the documentation table API documentation, state and onStateChange are apparently optional when calling createTable. However, they are required on the latest [email protected]

I was a bit confused between TableOptions and TableOptionsResolved.

https://github.com/TanStack/table/blob/af00c821b7943bc0f6d62a19b3ad514e3f315d75/packages/table-core/src/core/table.ts#L114

ℹ️ createTable is accepting TableOptionsResolvedwith state is required. Where by TableOptions has state as optional. May I know why we need both types?

Monosnap Table  TanStack Table Docs 2022-09-03 14-44-25

Monosnap Screenshot 2022-09-03 at 2 45 09 PM jpg 2022-09-03 14-45-53

2. Error throw when calling table.getHeaderGroups()

Because of the type errors on 1), I supplied the state as an empty object and onStateChange as an empty arrow function. The full source code can find at codesandbox, I followed the react basic example.

table = createTable({
  data,
  columns,
  state: {},
  onStateChange: () => {},
  getCoreRowModel: getCoreRowModel(),
  renderFallbackValue: null,
});

When trying to use table.getHeaderGroups(), it immediately throws errors

core.mjs:7643 ERROR TypeError: Cannot read properties of undefined (reading 'left')
    at index.production.js:11:2759
    at Object.getHeaderGroups (index.production.js:11:601)

If I try to console.log

console.log("state ", table.getState());
console.log("initial state ", table.initialState);

Only initialState have an initial value and state is having an empty object.

image

❌ Where is the issue

After looking into table-core source code, I found that core/headers.ts#L119 is trying to access to table.getState().columnPinning.left. Because table.getState() is an empty object, therefore columnPinning is undedefined and it CAN't access left.

✅ Workaround

  • Try to set the state with initialState before invoking anything else, it works!
// ✅ work well
table.setOptions(prev => ({
  ...prev,
  state: {
    ...prev.state,
    ...this.table.initialState
  }
}))
console.log('initial table state', this.table.state);

That's how the React wrapper did under the hood as well. Therefore if a user wants to use table-core, does it mean I have to set the state with initialState every time?

https://github.com/TanStack/table/blob/af00c821b7943bc0f6d62a19b3ad514e3f315d75/packages/react-table/src/index.tsx#L71

  • Strangely, I thought calling table.setState would do the same, but it DOESN'T work.
// ❌ doesn't work
this.table.setState(prev => ({
  ...prev,
  ...this.table.initialState
}))

Questions

  1. If state and onStateChange are required, which means the documentation is NOT up to date. Am I right to say that?
  2. What is the different between TableOptions and TableOptionsResolved?
  3. By following the doc freshly for table-core, do I have to call table.setOptions with initialState every time I want to use table-core? If it is, either the documentation needs to be updated, or the code needs to fix that.

Your minimal, reproducible example

https://codesandbox.io/s/tanstack-table-core-h86ggk?file=/src/index.ts:1702-1725

Steps to reproduce

  1. npm install @tanstack/table-core
  2. Copy the following code
Toggle code ➡️
import {
  createColumnHelper,
  createTable,
  getCoreRowModel
} from "@tanstack/table-core";

type Person = {
  firstName: string;
  lastName: string;
  age: number;
  visits: number;
  status: string;
  progress: number;
};

const data: Person[] = [
  {
    firstName: "tanner",
    lastName: "linsley",
    age: 24,
    visits: 100,
    status: "In Relationship",
    progress: 50
  },
  {
    firstName: "tandy",
    lastName: "miller",
    age: 40,
    visits: 40,
    status: "Single",
    progress: 80
  },
  {
    firstName: "joe",
    lastName: "dirte",
    age: 45,
    visits: 20,
    status: "Complicated",
    progress: 10
  }
];

const columnHelper = createColumnHelper<Person>();

const columns = [
  columnHelper.accessor("firstName", {
    cell: (info) => info.getValue(),
    footer: (info) => info.column.id
  }),
  columnHelper.accessor((row) => row.lastName, {
    id: "lastName",
    cell: (info) => info.getValue(),
    header: () => "Last Name",
    footer: (info) => info.column.id
  }),
  columnHelper.accessor("age", {
    header: () => "Age",
    cell: (info) => info.renderValue(),
    footer: (info) => info.column.id
  }),
  columnHelper.accessor("visits", {
    header: () => "Visits",
    footer: (info) => info.column.id
  }),
  columnHelper.accessor("status", {
    header: "Status",
    footer: (info) => info.column.id
  }),
  columnHelper.accessor("progress", {
    header: "Profile Progress",
    footer: (info) => info.column.id
  })
];

const table = createTable({
  data,
  columns,
  state: {},
  onStateChange: () => {},
  getCoreRowModel: getCoreRowModel(),
  renderFallbackValue: null
});

// vvvv Immediate issues here
console.log(table.getHeaderGroups());
  1. You'll see the errors

Expected behavior

If I supplied state: {}, the library would have set state to use initialState under the hood.

How often does this bug happen?

No response

Screenshots or Videos

No response

Platform

  • macOS, codesanbox Vanilla TS project, Angular CLI created project

react-table version

8.5.13

TypeScript version

No response

Additional context

No response

Terms & Code of Conduct

  • [X] I agree to follow this project's Code of Conduct
  • [X] I understand that if my bug cannot be reliable reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.

trungvose avatar Sep 03 '22 07:09 trungvose

Hi @trungk18 I am trying to implement table/core for angular as well, but we use Angular 8 on our project, and I had to rewrite all the core stuff and see how it works under the hood

let me share my workaround.

First I've created a wrapper service for that. Screenshot 2022-09-13 142704

then I use it to create a table instance.

Screenshot 2022-09-13 143109

From the first screen, you'll see that you have to add the initial state to the table before doing anything else. You are getting all necessary fields when you call createTable (from table/core)

SannyMatt avatar Sep 13 '22 12:09 SannyMatt

I recently tried to implement the table core package into a Stencil.js project. After a while I came up with a working implementation. Check this repository, it might give you some ideas for fixing your issue as well. Specifically I think that you are missing the flexRender() method. Check the stencil-adapter.tsx inside my repo.

ailequal avatar Sep 17 '22 08:09 ailequal

state and onStateChange should only be optional if using a framework adapter. we should correct this in the docs.

KevinVandy avatar Mar 21 '24 16:03 KevinVandy