komarovalexander / ka-table

Lightweight MIT React Table component with Sorting, Filtering, Grouping, Virtualization, Editing and many more
http://ka-table.com
MIT License
769 stars 56 forks source link

Add previous state in onDispatch action #411

Closed C0casio45 closed 4 months ago

C0casio45 commented 4 months ago

Hello,

I need to check if any row is similar to perform the same action on it in a table To do so, I somewhere in my code, having the two values (the old and the new one) at the same time

I may be wrong but I am not able to access to all the data in my custom cell In the useTable I am not able to access the old state (I have columnKey, rowKeyValue, type, and value)

Also I note that the type OnDispatchFunc contains action which is set as any, is it intended ?

komarovalexander commented 4 months ago

Hi @C0casio45 please provide stackblitz example what you are trying to achieve https://stackblitz.com/edit/table-custom-cell-ts?file=Demo.tsx

C0casio45 commented 4 months ago

Hi @komarovalexander

As long as StackBlitz is broken on my side and I can't save anything

here is the piece of code that I've added

const table = useTable({
  onDispatch: (action, tableProps) => {
    //for instance here oldValue is Moore because it's the first one
    const oldValue = 'Felicity Moore';
    if (tableProps.data?.some((d) => d.representative.name === oldValue)) {
      //finally update rows that have old value
    }
  },
});

I have also added

<Table
      table={table}
     ...
/>
komarovalexander commented 4 months ago

@C0casio45 can you reproduce it in any other online editor?

C0casio45 commented 4 months ago

just copy and paste this in the Demo.tsx and it's working

import './CustomCellDemo.scss';

import { DataType, Table, useTable } from 'ka-table';

import { EditingMode } from 'ka-table/enums';
import { ICellTextProps } from 'ka-table/props';
import React from 'react';
import dataArray from './data';

const table = useTable({
  onDispatch: (action, tableProps) => {
    //for instance here oldValue is Moore because it's the first one
    const oldValue = 'Felicity Moore';
    if (tableProps.data?.some((d) => d.representative.name === oldValue)) {
      //finally update rows that have old value
    }
  },
});

const CustomCell = ({ column, rowKeyValue, value }: ICellTextProps) => {
  const table = useTable({
    onDispatch: (action, tableProps) => {
      console.log(action, tableProps);
    },
  });
  return (
    <div
      onClick={() => {
        table.openEditor(rowKeyValue, column.key);
      }}
      className={value ? 'custom-cell-demo-loyal' : 'custom-cell-demo-no-loyal'}
    >
      {value ? 'Loyal Program Member' : 'No Loyal Programm'}
    </div>
  );
};

const CustomCellDemo = () => {
  return (
    <Table
table={table}
      columns={[
        {
          dataType: DataType.String,
          key: 'representative.name',
          width: 210,
          title: 'Representative',
        },
        {
          dataType: DataType.Boolean,
          key: 'company.hasLoyalProgram',
          style: { textAlign: 'center' },
          width: 200,
          title: 'Loyal Program',
        },
        {
          dataType: DataType.String,
          key: 'product.name',
          width: 110,
          title: 'Product',
        },
        {
          dataType: DataType.Number,
          key: 'product.price',
          style: { textAlign: 'right' },
          width: 130,
          title: 'Price',
        },
        {
          dataType: DataType.Date,
          key: 'firstDealDate',
          width: 150,
          title: 'First Deal Date',
        },
      ]}
      format={({ column, value }) => {
        if (column.key === 'product.price') {
          return `$${value}`;
        }
        if (column.dataType === DataType.Date) {
          return (
            value &&
            new Date(value).toLocaleDateString('en', {
              month: '2-digit',
              day: '2-digit',
              year: 'numeric',
            })
          );
        }
      }}
      data={dataArray}
      editingMode={EditingMode.Cell}
      rowKeyField={'id'}
      childComponents={{
        cellText: {
          content: (props) => {
            switch (props.column.key) {
              case 'company.hasLoyalProgram':
                return <CustomCell {...props} />;
            }
          },
        },
      }}
    />
  );
};

export default CustomCellDemo;
komarovalexander commented 4 months ago

looks like you need something like this:

import './CustomCellDemo.scss';

import { ActionType, EditingMode } from '../../lib/enums';
import { DataType, Table, useTable, useTableInstance } from '../../lib';

import { ICellTextProps } from '../../lib/props';
import React from 'react';
import dataArray from './data';

const CustomCell = ({ column, rowKeyValue, value }: ICellTextProps) => {
    const tableInstance = useTableInstance();
    return (
        <div
            onClick={() => {
                tableInstance.openEditor(rowKeyValue, column.key);
            }}
            className={value ? 'custom-cell-demo-loyal' : 'custom-cell-demo-no-loyal'}
        >
            {value ? 'Loyal Program Member' : 'No Loyal Programm'}
        </div>
    );
};

const table = useTable({
    onDispatch: (action, tableProps) => {
        if (action.type === ActionType.UpdateCellValue) {
            // for instance here oldValue is Moore because it's the first one
            const oldValue = 'Felicity Moore';
            // finally update rows that have old value
            tableProps.data && table.updateData(tableProps.data?.map(x => {
                if (x.representative.name === oldValue){
                    return {...x, representative: {...x.representative, name: 'newName'}}
                }
                return x;
            }))
        }
    },
});
const CustomCellDemo = () => {
    return (
        <Table
            table={table}
            columns={[
                {
                    dataType: DataType.String,
                    key: 'representative.name',
                    width: 210,
                    title: 'Representative',
                },
                {
                    dataType: DataType.Boolean,
                    key: 'company.hasLoyalProgram',
                    style: { textAlign: 'center' },
                    width: 200,
                    title: 'Loyal Program',
                },
                {
                    dataType: DataType.String,
                    key: 'product.name',
                    width: 110,
                    title: 'Product',
                },
                {
                    dataType: DataType.Number,
                    key: 'product.price',
                    style: { textAlign: 'right' },
                    width: 130,
                    title: 'Price',
                },
                {
                    dataType: DataType.Date,
                    key: 'firstDealDate',
                    width: 150,
                    title: 'First Deal Date',
                },
            ]}
            format={({ column, value }) => {
                if (column.key === 'product.price') {
                    return `$${value}`;
                }
                if (column.dataType === DataType.Date) {
                    return (
                        value &&
            new Date(value).toLocaleDateString('en', {
                month: '2-digit',
                day: '2-digit',
                year: 'numeric',
            })
                    );
                }
            }}
            data={dataArray}
            editingMode={EditingMode.Cell}
            rowKeyField={'id'}
            childComponents={{
                cellText: {
                    content: (props) => {
                        switch (props.column.key) {
                        case 'company.hasLoyalProgram':
                            return <CustomCell {...props} />;
                        }
                    },
                },
            }}
        />
    );
};

export default CustomCellDemo;
C0casio45 commented 4 months ago

No because in your example too the oldValue is set

The steps that I want are the followings :

komarovalexander commented 4 months ago

In my example you can add you custom logic here and it will work


const table = useTable({
    onDispatch: (action, tableProps) => {
        if (action.type === ActionType.UpdateCellValue) {
            // for instance here oldValue is Moore because it's the first one
            const oldValue = 'Felicity Moore';
            // finally update rows that have old value
            tableProps.data && table.updateData(tableProps.data?.map(x => {
                if (x.representative.name === oldValue){
                    return {...x, representative: {...x.representative, name: 'newName'}}
                }
                return x;
            }))
        }
    },
});
C0casio45 commented 4 months ago

Ok but how do I get the oldValue ?

komarovalexander commented 4 months ago

good question, I will add this value to the action soon, thanks

komarovalexander commented 4 months ago

hi @C0casio45 starting from version 10.0.0 prevState has been added to onDispatch action

action.oldValue has been deprecated and removed as not required anymore you can obtain it this way:

import { getValueByField } from 'ka-table/Utils/DataUtils';
//...
const table = useTable({
    onDispatch: (action, tableProps, prevState) => {
        if (action.type === ActionType.UpdateCellValue) {
            const oldValue = getValueByField(prevState.data?.find(x => x?.id === action.rowKeyValue), action.columnKey);

        }
    },
});