cstff
cstff

Reputation: 173

Fetch data for ag-grid in Remix

I'm learning Remix.run and trying to figure out how to face some requirements in advance. According to the documentation there is something called Resource Routes. But seems that a Resource Route need to be linked from a Link component:

<Link to="pdf" reloadDocument>
    View as PDF
</Link>

I can't found any example showing how to create a simple route that can return data for a grid component, for example ag-grid.

There is any way to do this inside Remix or I will need to implement an external endpoint?

Upvotes: 1

Views: 995

Answers (1)

joon_bug
joon_bug

Reputation: 57

AG Grid wrote a blog post about this not too long ago. Here is the article: https://blog.ag-grid.com/using-ag-grid-react-ui-with-remix-run/.

First, set up a resource route using Remix's conventions outlined here: https://remix.run/docs/en/v1/guides/resource-routes#creating-resource-routes

The resource route should export only a loader function that retrieves the data you want to load into the table.

Note: This example also uses logic for infinite scrolling

app/routes/posts/$id/postsGridData.ts

import type { LoaderFunction } from 'remix';
import { db } from '~/utils/db.server'; // Prisma ORM being used

export const loader: LoaderFunction = ({ request }) => {
  const from = Number(new URL(request.url).searchParams.get("from"));
  const to = Number(new URL(request.url).searchParams.get("to"));

  if (from >= 0 && to > 0) {
    const posts = await db.post.findMany({
      skip: from,
      take: to - from,
      select: {
        id: true,
        title: true,
        updatedAt: true,
        author: {
          select: {
            email: true,
            name: true,
          },
        },
      },
    });

    return posts;
  }
  return [];
}

Next, in the route with your AGGridReact component, you'll add the following:

  • A Remix Fetcher to get the data from your resource route without a route change
  • An onGridReady function that loads the next batch of data
  • Some local state to manage the fetching logic
  • A datasource to plug into AG Grid
  • A useEffect function to trigger when the fetcher has loaded
  • AgGridReact component with added parameters rowModelType and onGridReady

app/routes/posts.tsx

import { useFetcher } from 'remix';
import { useCallback, useEffect, useState } from 'react';
import { AgGridReact } from "ag-grid-react";
import AgGridStyles from "ag-grid-community/dist/styles/ag-grid.css";
import AgThemeAlpineStyles from "ag-grid-community/dist/styles/ag-theme-alpine.css";

export default function PostsRoute() {
  const [isFetching, setIsFetching] = useState(false);
  const [getRowParams, setGetRowParams] = useState(null);
  const posts = useFetcher();
  
  const onGridReady = useCallback((params) => {
    const datasource = {
    getRows(params) {
      if (!isFetching) {
        posts.load(`/posts?from=${params.startRow}&to=${params.endRow}`);

        setGetRowParams(params);
        setIsFetching(true);
      }
    },
  };

  params.api.setDatasource(datasource);
  }, []);

  useEffect(() => {
  // The useEffect hook in this code will trigger when the fetcher has 
  // loaded new data. If a successCallback is available, it’ll call it, 
  // passing the loaded data and the last row to load
  if (getRowParams) {
    const data = posts.data || [];

    getRowParams.successCallback(
      data,
      data.length < getRowParams.endRow - getRowParams.startRow
        ? getRowParams.startRow
        : -1
    );
  }

  setIsFetching(false);
  setGetRowParams(null);
}, [posts.data, getRowParams]);

  const columnDefs = [/* Your columnDefs */];

  return (
    <div className="ag-theme-alpine" style={{ width: "100%", height: "100%" }}>
      <AgGridReact
        columnDefs={columnDefs}
        rowModelType="infinite"
        onGridReady={onGridReady}
      />
    </div>
  );
}

Upvotes: 2

Related Questions