Create a table
info
Here we want to make a table list similar to the <ArticlesList />.
In element folder in the previously created modules folder, create a file newList.tsx.
First, you will need columns for your table.
Create your columns
const columns = [
{
title: "d:name",
dataIndex: "name",
key: "name",
},
{
title: "d:additionalDescription",
dataIndex: "additionalDescription",
key: "additionalDescription",
},
{
title: "d:code",
dataIndex: "code",
key: "code",
},
{
title: "d:status",
dataIndex: "status",
key: "status",
},
{
title: "actions:actions",
key: "actions",
render: (record: { id: string }) => (
<Space>
<LinkButton
icon={<EyeTwoTone />}
path={pathParams("/article/[id]", record.id)}
/>
</Space>
),
},
];
caution
For internationnalization, the title key should match this format in order to work : namespaces:translation (d:code). See more about Internationnalization
You can create your own column using this pattern. The last column object has the actions key and it can receive components to trigger some action in the render property.
Handle table state
In order to display data and act on the table you will need 2 local states. One for the data and another for pagination.
const [articles, setArticles] = useState<DataQueryType>();
const [pagination, setPagination] = useState<PaginationType>({
total: undefined,
current: DEFAULT_PAGE_NUMBER,
itemsPerPage: DEFAULT_ITEMS_PER_PAGE
});
The pagination state is an object that holds the total number of available data => total, the current page displaying the data in the table => current and the number of items that will be displayed on the page => itemsPerPage.
info
DEFAULT_PAGE_NUMBER & DEFAULT_ITEMS_PER_PAGE are static variables that you can customize to your need in /helpers/utils/constant.ts. More about helpers
The pagination will be handled in the AppTable component. So we need a callback that will be passed to AppTable component.
// make wrapper function to give child
const onChangePagination = useCallback(
(currentPage, itemsPerPage) => {
// Re fetch data for new current page or items per page
setPagination({
total: articles?.count,
current: currentPage,
itemsPerPage: itemsPerPage,
});
},
[setPagination, articles],
);
The articles state will behold all fetched articles from the graphQL query.
Get your data
Cella frontend use react-query and GraphQL to fetch all data we need.
Type-Safety and Code Generation
We used GraphQL-Codegen to generate ready-to-use React Hooks, based on all GraphQL operations. You can find more details and examples here.
Create new query
In graphql folder, you can define any mutation or query you want by creating a file whatever.graphql. Then just put the graphql operation.
query GetAllArticles(
$filters: ArticleSearchFilters
$orderBy: [ArticleOrderByCriterion!]
$page: Int!
$itemsPerPage: Int!
) {
articles(filters: $filters, orderBy: $orderBy, page: $page, itemsPerPage: $itemsPerPage) {
count
itemsPerPage
totalPages
results {
...
}
}
}
Run this command :
yarn gen
This will generate custom type safe hooks directly from your GraphQL schema and GraphQL operations. The output is located in generated/graphql.ts. You will find all available hooks with examples in it.
The generated type safe hooks for articles was useGetAllArticlesQuery()
Create new hook
After that, we created a custom hooks to make our code cleaner :
const useArticles = (
search: any,
page: number,
itemsPerPage: number,
sort: any,
) => {
const { graphqlRequestClient } = useAuth();
// default sort by creation date
const sortByDate = {
field: "created",
ascending: false,
};
let newSort;
if (sort === null) {
newSort = sortByDate;
} else {
newSort = sort;
}
const articles = useGetAllArticlesQuery<Partial<GetAllArticlesQuery>, Error>(
graphqlRequestClient,
{
filters: search,
orderBy: newSort,
page: page,
itemsPerPage: itemsPerPage,
},
);
return articles;
};
Then call this hook in your Element list file.
const { isLoading, data, error } = useArticles(
searchCriteria,
pagination.current,
pagination.itemsPerPage,
sort,
);
You will have 3 variables:
isLoadingto know if the query is finish.datathat hold the result of the query.errorthe error message if an error occured.
Handle fetched data
If any data change we need to set the local state (here articles) to get the newest data and set pagination as there may be more pages after that change. We will use an effect in that case.
useEffect(() => {
if (data) {
setArticles(data?.articles); // set articles local state with new data
setPagination({
...pagination,
total: data?.articles?.count, // may change total items
});
}
}, [data]);
Sort columns
You can sort any columns in your table. In order to sort a column you will need an order local state called sort.
A column can be sorted by ascendent or descendent or not sort.
const [sort, setSort] = useState<any>(null);
Then add 2 new key to the column that you want to be sortable :
sortershowSorterTooltip
info
The sorter value is an object that has a multiple key. Is value should be a number and should match this format : n+1.
const columns = [
{
title: "d:name",
dataIndex: "name",
key: "name",
sorter: {
multiple: 1,
},
showSorterTooltip: false,
},
{
title: "d:additionalDescription",
dataIndex: "additionalDescription",
key: "additionalDescription",
sorter: {
multiple: 2,
},
showSorterTooltip: false,
},
{
title: "d:code",
dataIndex: "code",
key: "code",
sorter: {
multiple: 3,
},
showSorterTooltip: false,
},
];
In order to really sort the table,we need a function that is triggered when the table change.
const handleTableChange = async (
_pagination: any,
_filter: any,
sorter: any,
) => {
await setSort(orberByFormater(sorter));
};
Display your data
AppTable is a smart component that will create a table list with your data. It will automatically create the necessary filter settings for your columns.
You will need to pass a unique type, an columns array and a dataset and some other properties. See all properties of AppTable
import { AppTable } from "@components";
<AppTable
type="articles"
columns={columns}
data={articles!.results}
pagination={pagination}
isLoading={isLoading}
setPagination={onChangePagination}
onChange={handleTableChange}
/>;