Skip to content
Source code Git
vue
<template>
    <VGrid
        :source="source"
        :columns="rvColumns"
        hide-attribution
        @beforeedit="handleEdit"
    />
</template>

<script setup lang="ts">
import { VGrid, type ColumnProp } from '@revolist/vue3-datagrid'

import {
    useVueTable,
    getCoreRowModel,
    type ColumnDef,
    type RowData,
} from '@tanstack/vue-table'

import { computed, ref } from 'vue'
import { tanstackToRvGridColumns } from '../tanstack/utils'
import { makeData, type Person } from '../makeData'

declare module '@tanstack/vue-table' {
    interface TableMeta<TData extends RowData> {
        updateData: (
            rowIndex: number,
            columnId: ColumnProp,
            value: unknown
        ) => void
    }
}

// Define columns according tanstack guide
const columns: ColumnDef<Person>[] = [
    {
        header: 'Name',
        columns: [
            {
                accessorKey: 'firstName',
                header: 'First Name',
            },
            {
                accessorKey: 'lastName',
                header: 'Last Name',
            },
        ],
    },
]
const data = ref<Person[]>(makeData(5))

// define tanstack table
const table = useVueTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
    meta: {
        updateData: (rowIndex: number, columnId: ColumnProp, value: any) => {
            data.value = data.value.map((row, index) => {
                if (index === rowIndex) {
                    return {
                        ...data.value[rowIndex]!,
                        [columnId]: value,
                    }
                }
                return row
            })
        },
    },
})

// get data from tanstack table
const source = computed(() => {
    const rows = table.getRowModel().flatRows
    return rows
})

const rvColumns = computed(() => {
    // transform tanstack to revogrid format
    return tanstackToRvGridColumns(table.getAllColumns())
})

function handleEdit(e: CustomEvent<HTMLRevoGridElementEventMap['beforeedit']>) {
    e.preventDefault()
    table.options.meta?.updateData(
        e.detail.model.index,
        e.detail.prop,
        e.detail.val
    )
}
</script>
tsx
import React, { useState, useMemo, useCallback } from 'react';
import { RevoGrid, type BeforeSaveDataDetails, type RevoGridCustomEvent } from '@revolist/react-datagrid';
import {
  useReactTable,
  getCoreRowModel,
  type ColumnDef,
} from '@tanstack/react-table';
import { tanstackToRvGridColumns } from '../tanstack/utils';
import { makeData, type Person } from '../makeData';

// Define TanStack columns
const columns: ColumnDef<Person>[] = [
  {
    header: 'Name',
    columns: [
      {
        accessorKey: 'firstName',
        header: 'First Name',
      },
      {
        accessorKey: 'lastName',
        header: 'Last Name',
      },
    ],
  },
];

const ExampleIntegration = () => {
  const [data, setData] = useState(makeData(5));

  // Set up TanStack table instance
  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
    meta: {
      updateData: (rowIndex, columnId, value) => {
        setData((old) =>
          old.map((row, index) => {
            if (index === rowIndex) {
              return {
                ...old[rowIndex],
                [columnId]: value,
              };
            }
            return row;
          })
        );
      },
    },
  });

  // Extract data and columns for RevoGrid
  const source = useMemo(() => {
    const rows = table.getRowModel().flatRows;
    return rows;
  }, [table]);

  const rvColumns = useMemo(() => {
    // Convert TanStack column definition to RevoGrid format
    return tanstackToRvGridColumns(table.getAllColumns());
  }, [table]);

  const handleEdit = useCallback((e: RevoGridCustomEvent<BeforeSaveDataDetails>) => {
    e.preventDefault();
    const { model, prop, val } = e.detail;
    table.options.meta?.updateData(model.index, prop, val);
  }, [table]);

  return (
    <RevoGrid
      source={source}
      columns={rvColumns}
      onBeforeedit={handleEdit}
      hideAttribution
    />
  );
};

export default ExampleIntegration;
ts
// Helper functions to convert tanstack to revogrid format
import type { ColumnGrouping, ColumnRegular } from "@revolist/vue3-datagrid";
import type { Column } from "@tanstack/vue-table";

export function tanstackToRvGridColumns(tanstackColumns: Column<any>[]) {
  return tanstackColumns.map((col) => {
    // Check if this column has children (group columns)
    if (col.columns?.length) {
      const rvGroup: ColumnGrouping = {
        name: col.columnDef.header,
        children: tanstackToRvGridColumns(col.columns),
      };
      return rvGroup; // Recursive call for child columns
    }
    const rvColumn: ColumnRegular = {
      prop: col.id, // Use col.id or accessorKey
      name: col.columnDef.header, // Direct mapping for column header
      sortable: !!col.getCanSort(), // Check if the column is sortable
      filter: col.getCanFilter() ? "customFilterType" : false, // Handle filters
    };

    // Handle custom sorting functions via cellCompare
    const sortingFn = col.getSortingFn();
    if (!!sortingFn) {
      rvColumn.cellCompare = (_, rowA: any, rowB: any) =>
        sortingFn(rowA, rowB, col.id);
      rvColumn.sortable = true; // Ensure sorting is enabled
    }

    // Handle filtering logic if provided
    const filterFn = col.getFilterFn();
    if (filterFn) {
      rvColumn.filter = "customFilterType"; // Assume custom type for filtering
    }

    rvColumn.cellParser = (model) => {
      return model.renderValue(col.id);
    };

    return rvColumn;
  });
}
ts
import { faker } from '@faker-js/faker'

export type Person = {
  avatar: string
  firstName: string
  lastName: string
  name: string
  age: number
  visits: number
  progress: number
  status: 'relationship' | 'complicated' | 'single'
  subRows?: Person[]
}

const range = (len: number) => {
  const arr: number[] = []
  for (let i = 0; i < len; i++) {
    arr.push(i)
  }
  return arr
}

const newPerson = (): Person => {
  const firstName = faker.person.firstName()
  const lastName = faker.person.lastName()
  return {
    avatar: faker.image.avatar(),
    firstName,
    lastName,
    name: `${firstName} ${lastName}`,
    age: faker.number.int(40),
    visits: faker.number.int(1000),
    progress: faker.number.int(100),
    status: faker.helpers.shuffle<Person['status']>([
      'relationship',
      'complicated',
      'single',
    ])[0]!,
  }
}

export function makeData(...lens: number[]) {
  const makeDataLevel = (depth = 0): Person[] => {
    const len = lens[depth]!
    return range(len).map((): Person => {
      return {
        ...newPerson(),
        subRows: lens[depth + 1] ? makeDataLevel(depth + 1) : undefined,
      }
    })
  }

  return makeDataLevel()
}

Revogrid is a powerful data grid library made by Revolist OU.