How to increment a cell in AG Grid React tabel? - javascript

Pretty new with AG Grid library and stuck on updating the cells.
In reality, I need to do the task with dates, but just to keep it simple, I'll explain my problem with simple numbers.
I have
Start, which is 1.
Stop, which is already defined
End
Duration, which is already defined
My goal
Start = Duration + End
End = Start + Stop
Here is what I have so far
Desired result
Sandbox Link and code below
import React from "react";
import { AgGridReact } from "ag-grid-react";
import "./styles.css";
import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-alpine.css";
function App() {
const start = 1;
const [gridApi, setGridApi] = React.useState(null);
const [gridColumnApi, setGridColumnApi] = React.useState(null);
const columnDefs = [
{
headerName: "Name",
field: "name"
//valueGetter: (params) => console.log(params)
},
{
headerName: "start",
field: "start",
valueGetter: (params) => {
if (params.node.rowIndex !== 0) {
return params.getValue("end") + params.data.duration;
} else {
return start;
}
}
},
{ headerName: "stop", field: "stop" },
{
headerName: "end",
colId: "end",
valueGetter: (params) => {
return params.data.start + params.data.stop;
}
},
{
headerName: "duration",
field: "duration",
colId: "duration"
}
];
const rowData = React.useMemo(
() => [
{
name: "John",
stop: 10
},
{
name: "David",
stop: 15
},
{
name: "Dan",
stop: 20
}
],
[]
);
const durationArray = [5, 8, 6];
const rowDataWithStart = React.useMemo(() => {
if (durationArray) {
return (
rowData &&
rowData.map((row, i) => ({
...row,
start: start,
duration: durationArray[i]
}))
);
}
}, [start, rowData, durationArray]);
const defaultColDef = {
flex: 1,
editable: true
};
const onGridReady = (params) => {
setGridApi(params.api);
setGridColumnApi(params.columnApi);
};
return (
<div className="App">
<h1 align="center">React-App</h1>
<div className="ag-theme-alpine">
<AgGridReact
columnDefs={columnDefs}
rowData={rowDataWithStart}
defaultColDef={defaultColDef}
domLayout={"autoHeight"}
onGridReady={onGridReady}
></AgGridReact>
</div>
</div>
);
}
export default App;
Any help will be appreciated

you can use valueGetter for this. I have modified the valueGetter in you code
const columnDefs = [
{
headerName: "Name",
field: "name"
//valueGetter: (params) => console.log(params)
},
{
field: "start",
valueGetter: ({ data }) => {
const end = data.stop + data.start
return data.duration + end;
}
},
{ field: "stop" },
{
field: "end",
valueGetter: ({ data }) => {
return data.start + data.stop
}
},
{
headerName: "duration",
field: "duration"
}
];

Related

AG Grid TypeScript in-line cell editing testing jest

I'm trying to create jest tests in order to test the functionality of my ag-grid table.
I currently have tests for expecting the default data in the grid, and testing the functionality of a button which adds an extra row of data to the grid.
I'm trying to edit one of my cells using in-line editing by simulating a double click on the cell I want to be edited. Then followed by a userEvent.type. However the cell never seems to update. I'm not sure if this is because the data hasn't been updated yet due to the asynchronous behaviour or if the simulated typing/click isn't working.
This is my test which is failing:
test("tests the inline cell editing", async () => {
const onClick = jest.fn();
render(<DummyGrid onClick={onClick} />);
const row = screen
.getAllByRole("row")
.filter((item) => item.getAttribute("row-id") === "1");
fireEvent.doubleClick(row[1]);
userEvent.type(row[1], "GT{enter}");
await waitFor(() => {
expect(screen.getByText("GT")).toBeInTheDocument();
});
});
And the following is the DummyGrid ag-grid component:
import React, { useState } from "react";
import { AgGridReact } from "ag-grid-react/lib/agGridReact";
import { ColDef, ValueSetterParams } from "ag-grid-community";
import GridButton from "./GridButton";
import Car from "./car";
import { Button } from "react-bootstrap";
import "ag-grid-community/dist/styles/ag-grid.css";
import "ag-grid-community/dist/styles/ag-theme-alpine-dark.css";
const initialState: Array<Car> = [
{ id: "0", make: "Toyota", modelName: "Celica", price: 35000 },
{ id: "1", make: "Ford", modelName: "Mondeo", price: 32000 },
{ id: "2", make: "Porsche", modelName: "Boxter", price: 70000 },
];
const fieldName = (name: keyof Car) => name;
function getRowNodeId(data: Car) {
return data.id;
}
function onGridReady(params: object) {
// console.log(params);
}
function onRowDataChanged(data: object) {
// console.log(data);
}
const columnDefs: ColDef[] = [
{
headerName: "Make",
field: fieldName("make"),
editable: true,
},
{
headerName: "Model",
field: fieldName("modelName"),
editable: true,
// valueSetter: (params: ValueSetterParams) => {
// onRowDataChanged(params);
// },
},
{
headerName: "Price",
field: fieldName("price"),
editable: true,
},
{
field: "Button",
cellRenderer: "gridButton",
cellRendererParams: {
onClicked: function (
id: string,
make: string,
modelName: string,
price: number
) {
// console.log(id, make, modelName, price);
},
},
},
];
const gridOptions = {
immutableData: true,
suppressScrollOnNewData: true,
columnDefs: columnDefs,
frameworkComponents: {
gridButton: GridButton,
},
};
interface Props {
onClick: () => void;
}
const DummyGrid: React.FC<Props> = ({ onClick }) => {
const [rowData, setRowData] = useState(initialState);
function addData() {
console.log("test");
const newRow: Car = {
id: "3",
make: "Land Rover",
modelName: "Defender",
price: 40000,
};
// console.log(rowData);
setRowData((oldData) => [...oldData, newRow]);
onClick();
}
return (
<div>
<Button data-testid="myButton" onClick={addData}>
Add New Value
</Button>
<div
className="ag-theme-alpine-dark"
style={{ height: "300px", width: "802px" }}
>
<AgGridReact
columnDefs={columnDefs}
defaultColDef={{
sortable: true,
}}
rowData={rowData}
gridOptions={gridOptions}
onGridReady={onGridReady}
onRowDataChanged={onRowDataChanged}
getRowNodeId={getRowNodeId}
suppressColumnVirtualisation={true}
></AgGridReact>
</div>
</div>
);
};
export default DummyGrid;
Any help or advice would be much appreciated. I have researched and found a very small amount of help on testing ag-grid with jest, and nothing on testing in-line ag-grid editing with jest, only the testing of separate buttons which update the grid content.

REACTJ - convert class component to functionnal component

i'm new to react and i'm trying to convert this class based component to a functionnal component but i get an error of state, how can i convert it please ?
This is my components :)
sandbox link
Thank you
In this example, it is quite straight forward as there are no component life cycle methods. You can just define all the methods in the function, and return the component.
function Demo() {
const [state, setState] = React.useState({
expandedKeys: [],
autoExpandParent: true,
checkedKeys: [],
allCheckedKeys: [],
selectedKeys: [],
newTreeView: false,
newTreeData: []
});
const onExpand = (expandedKeys) => {
console.log("onExpand", expandedKeys);
// if not set autoExpandParent to false, if children expanded, parent can not collapse.
// or, you can remove all expanded children keys.
setState({
...state,
expandedKeys,
autoExpandParent: false
});
};
const onCheck = (checkedKeys, e) => {
const allCheckedKeys = [...checkedKeys, ...e.halfCheckedKeys];
console.log("onCheck", allCheckedKeys);
console.log(createNewTreeData(treeData, allCheckedKeys));
setState((prevState) => ({
...prevState,
allCheckedKeys,
checkedKeys
}));
};
const onSelect = (selectedKeys, info) => {
console.log("onSelect", info);
setState({ ...state, selectedKeys });
};
const renderTreeNodes = (data) =>
data.map((item) => {
if (item.children) {
return (
<TreeNode title={item.title} key={item.key} dataRef={item}>
{renderTreeNodes(item.children)}
</TreeNode>
);
}
return <TreeNode {...item} />;
});
const createTree = () => {
setState((prevState) => ({
...prevState,
newTreeView: true,
newTreeData: createNewTreeData(treeData, prevState.allCheckedKeys)
}));
};
return (
<>
<Tree
checkable
onExpand={onExpand}
expandedKeys={state.expandedKeys}
autoExpandParent={state.autoExpandParent}
onCheck={onCheck}
checkedKeys={state.checkedKeys}
onSelect={onSelect}
selectedKeys={state.selectedKeys}
>
{renderTreeNodes(treeData)}
</Tree>
<button onClick={createTree}>Validate</button>
{state.newTreeView && <Tree>{renderTreeNodes(state.newTreeData)}</Tree>}
</>
);
}
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import './index.css';
import { Tree } from 'antd';
const treeData = [
{
title: '0-0',
key: '0-0',
children: [
{
title: '0-0-0',
key: '0-0-0',
children: [
{
title: '0-0-0-0',
key: '0-0-0-0',
},
{
title: '0-0-0-1',
key: '0-0-0-1',
},
{
title: '0-0-0-2',
key: '0-0-0-2',
},
],
},
{
title: '0-0-1',
key: '0-0-1',
children: [
{
title: '0-0-1-0',
key: '0-0-1-0',
},
{
title: '0-0-1-1',
key: '0-0-1-1',
},
{
title: '0-0-1-2',
key: '0-0-1-2',
},
],
},
{
title: '0-0-2',
key: '0-0-2',
},
],
},
{
title: '0-1',
key: '0-1',
children: [
{
title: '0-1-0-0',
key: '0-1-0-0',
},
{
title: '0-1-0-1',
key: '0-1-0-1',
},
{
title: '0-1-0-2',
key: '0-1-0-2',
},
],
},
{
title: '0-2',
key: '0-2',
},
];
const Demo = () => {
const [expandedKeys, setExpandedKeys] = useState(['0-0-0', '0-0-1']);
const [checkedKeys, setCheckedKeys] = useState(['0-0-0']);
const [selectedKeys, setSelectedKeys] = useState([]);
const [autoExpandParent, setAutoExpandParent] = useState(true);
const onExpand = (expandedKeysValue) => {
console.log('onExpand', expandedKeysValue); // if not set autoExpandParent to false, if children expanded, parent can not collapse.
// or, you can remove all expanded children keys.
setExpandedKeys(expandedKeysValue);
setAutoExpandParent(false);
};
const onCheck = (checkedKeysValue) => {
console.log('onCheck', checkedKeysValue);
setCheckedKeys(checkedKeysValue);
};
const onSelect = (selectedKeysValue, info) => {
console.log('onSelect', info);
setSelectedKeys(selectedKeysValue);
};
return (
<Tree
checkable
onExpand={onExpand}
expandedKeys={expandedKeys}
autoExpandParent={autoExpandParent}
onCheck={onCheck}
checkedKeys={checkedKeys}
onSelect={onSelect}
selectedKeys={selectedKeys}
treeData={treeData}
/>
);
};
ReactDOM.render(<Demo />, document.getElementById('container'));
I have updated the code using ES6 arrow functions resulting in shorter and simpler code than traditional functional components.
import React,{useState} from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Tree } from "antd";
const { TreeNode } = Tree;
const treeData = [
{
title: "0-0",
key: "0-0",
children: [
{
title: "0-0-0",
key: "0-0-0",
children: [
{ title: "0-0-0-0", key: "0-0-0-0" },
{ title: "0-0-0-1", key: "0-0-0-1" },
{ title: "0-0-0-2", key: "0-0-0-2" }
]
},
{
title: "0-0-1",
key: "0-0-1",
children: [
{ title: "0-0-1-0", key: "0-0-1-0" },
{ title: "0-0-1-1", key: "0-0-1-1" },
{ title: "0-0-1-2", key: "0-0-1-2" }
]
},
{
title: "0-0-2",
key: "0-0-2"
}
]
},
{
title: "0-1",
key: "0-1",
children: [
{ title: "0-1-0-0", key: "0-1-0-0" },
{ title: "0-1-0-1", key: "0-1-0-1" },
{ title: "0-1-0-2", key: "0-1-0-2" }
]
},
{
title: "0-2",
key: "0-2"
}
];
const createNewTreeData = (treeData, checkedKeys) => {
return treeData.reduce((acc, treeDataItem) => {
if (checkedKeys.includes(treeDataItem.key)) {
if (treeDataItem.children) {
acc.push({
...treeDataItem,
children: createNewTreeData(treeDataItem.children, checkedKeys)
});
} else {
acc.push(treeDataItem);
}
}
return acc;
}, []);
};
const Demo =()=> {
const [state,setState] = useState({
expandedKeys: [],
autoExpandParent: true,
checkedKeys: [],
allCheckedKeys: [],
selectedKeys: [],
newTreeView: false,
newTreeData: []
});
const onExpand = (expandedKeys) => {
console.log("onExpand", expandedKeys);
// if not set autoExpandParent to false, if children expanded, parent can not collapse.
// or, you can remove all expanded children keys.
setState({
expandedKeys,
autoExpandParent: false
});
};
const onCheck = (checkedKeys, e) => {
const allCheckedKeys = [...checkedKeys, ...e.halfCheckedKeys];
console.log("onCheck", allCheckedKeys);
console.log(createNewTreeData(treeData, allCheckedKeys));
setState((prevState) => ({
...prevState,
allCheckedKeys,
checkedKeys
}));
};
const onSelect = (selectedKeys, info) => {
console.log("onSelect", info);
setState({ selectedKeys });
};
const renderTreeNodes = (data) =>
data.map((item) => {
if (item.children) {
return (
<TreeNode title={item.title} key={item.key} dataRef={item}>
{renderTreeNodes(item.children)}
</TreeNode>
);
}
return <TreeNode {...item} />;
});
const createTree = () => {
setState((prevState) => ({
...prevState,
newTreeView: true,
newTreeData: createNewTreeData(treeData, prevState.allCheckedKeys)
}));
};
return (
<>
<Tree
checkable
onExpand={onExpand}
expandedKeys={state.expandedKeys}
autoExpandParent={state.autoExpandParent}
onCheck={onCheck}
checkedKeys={state.checkedKeys}
onSelect={onSelect}
selectedKeys={state.selectedKeys}
>
{renderTreeNodes(treeData)}
</Tree>
<button onClick={createTree}>Validate</button>
{state.newTreeView && (
<Tree>{renderTreeNodes(state.newTreeData)}</Tree>
)}
</>
);
}
ReactDOM.render(<Demo />, document.getElementById("container"));

When a prop is changing const is backing to its initial values

I have this component which is a filter for a table..
handleSearch function is responsible to update const filters... its work perfectly when dataIndex props is the same, but when it changes, filters value is backing to it's initial value, an empty array.
I can't manage to resolve it, I've already console log everything.
import React, { useState, } from "react";
import { SearchOutlined } from "#ant-design/icons";
import { Select, Button, Space } from "antd";
const TableFilter = (props) => {
const {
filterType,
filterMode,
filterOptions,
FilterSelectOnFocus,
dataIndex,
setSelectedKeys,
selectedKeys,
confirm,
clearFilters,
} = props;
const [filters, setFilters] = useState([]);
const SelectFilter = (
<Select
style={{ width: 188, marginBottom: 8, display: "block" }}
type={filterType}
mode={filterMode}
name={dataIndex}
value={selectedKeys}
optionFilterProp="children"
placeholder={`Search ${dataIndex}`}
onFocus={FilterSelectOnFocus}
showSearch
onChange={(value) => setSelectedKeys(value ? value : [])}
getPopupContainer={(trigger) => trigger}
notFoundContent
>
{filterOptions?.map((type, key) => (
<Select.Option value={type.value} key={key}>
{type.label}
</Select.Option>
))}
</Select>
);
const defaultFilterTypes = [
{
type: "select",
element: SelectFilter,
},
];
const handleFilterType = () => {
const type = defaultFilterTypes.find((types) => types.type === filterType);
return type.element;
};
const handleSearch = () => {
console.log(filters) //is empty when dataIndex value change, when it's is the same it get the update value of the 75 line
confirm();
const newFilterValues = [...filters]
const index = newFilterValues.findIndex(newValue => newValue.searchedColumn === dataIndex)
if(index === -1){
newFilterValues.push({ searchText: selectedKeys, searchedColumn: dataIndex})
}
else{
newFilterValues[index] = {searchText: selectedKeys, searchedColumn: dataIndex}
}
setFilters(newFilterValues)
}
const handleReset = () => {
console.log('reset');
clearFilters();
setFilters({ searchText: "" });
setSelectedKeys([]);
};
return (
<div style={{ padding: 8 }}>
{handleFilterType()}
<Space>
<Button
type="primary"
onClick={() => handleSearch()}
icon={<SearchOutlined />}
size="small"
style={{ width: 90 }}
>
Search
</Button>
<Button
onClick={() => handleReset()}
size="small"
style={{ width: 90 }}
>
Reset
</Button>
</Space>
</div>
);
};
export default TableFilter;
Table Component
import React, { useEffect, useState } from "react";
import { Table } from "antd";
import { getTransactions } from "../../../../api/Transactions";
import { formatCnpjCpf, formatCurrency } from "../../../../utils/masks";
import TableFilter from "../../../../shared-components/ant-design/containers/TableFilters";
import { getPartnersAsOptions } from "../../../../api/Partners";
const Insider = (props) => {
const [data, setData] = useState([]);
const [paginationValues, setPaginationValues] = useState({
current: 1,
pageSize: 50,
total: 0,
position: ["topRight"],
});
const [partners, setPartners] = useState([{value: null, label: 'carregando...'}])
const context = "insider";
function getColumnSearchProps(
dataIndex,
filterType,
filterMode,
filterOptions,
FilterSelectOnFocus
) {
return {
filterDropdown: ({
setSelectedKeys,
selectedKeys,
confirm,
clearFilters,
}) => {
return (
<TableFilter
dataIndex={dataIndex}
filterType={filterType}
filterMode={filterMode}
filterOptions={filterOptions}
FilterSelectOnFocus={FilterSelectOnFocus}
setSelectedKeys={setSelectedKeys}
selectedKeys={selectedKeys}
confirm={confirm}
clearFilters={clearFilters}
/>
);
},
};
}
async function getPartners(){
if(partners.length > 2){
return
}
const response = await getPartnersAsOptions(paginationValues)
setPartners(response.data)
}
const columns = [
{
dataIndex: ["transactionType", "desc"],
title: "Tipo de Transação",
sorter: true,
key: "orderTransactionType",
...getColumnSearchProps("orderTransactionType"),
},
{
dataIndex: "transactionDate",
title: "Data Transação",
key: "orderTransactionDate",
sorter: true,
...getColumnSearchProps("orderTransactionDate"),
},
{
title: "Nome origem",
dataIndex: ["source", "name"],
sorter: true,
key: "orderSourceCustomerName",
},
{
render: (render) => formatCnpjCpf(render.source.document.value),
title: "Documento origem",
key: "sourceCustomer",
...getColumnSearchProps("sourceCustomer", "select", "tags")
},
{
title: "Nome destino",
dataIndex: ["target", "name"],
sorter: true,
key: "orderTargetCustomerName",
},
{
render: (render) => formatCnpjCpf(render.target.document.value),
title: "Documento destino",
},
{
render: (render) => formatCurrency(render.value),
title: "Valor da transação",
key: "orderValue",
sorter: true,
align: "right",
},
{
render: (render) => formatCurrency(render.chargedTariff),
title: "Tarifa",
key: "orderChargedTariff",
sorter: true,
align: "right",
},
{
render: (render) => formatCurrency(render.cost),
title: "Custo",
key: "orderCost",
sorter: true,
align: "right",
},
{
render: (render) => formatCurrency(render.revenue),
title: "Receita",
key: "orderRevenue",
sorter: true,
align: "right",
},
{
title: "Parceiro",
name: "Parceiro",
dataIndex: ["partner", "name"],
key: "orderPartnerName",
sorter: true,
align: "center",
...getColumnSearchProps(
"orderPartnerName",
"select",
"multiple",
partners,
getPartners)
},
{
title: "id da transação",
name: "id da transação",
dataIndex: "id",
},
];
useEffect(function transactions() {
async function fetchTransactions() {
const response = await getTransactions(context, paginationValues);
if (response) {
const { data, pagination } = response;
setData(data);
setPaginationValues(pagination);
}
}
fetchTransactions();
// eslint-disable-next-line
}, []);
return <Table dataSource={data} columns={columns} />;
};
export default Insider;
You could move this piece of code
const [filters, setFilters] = useState([]);
In a higher level

How can change boolean type icons to oposite

I'm want the empty key called archive has the check and with the values "true" has the line icon.
Here is the example: I want the opposite to the column status. Without change the tableIcons.js
Here is the code and codesandbox example:
import React, { useState } from "react";
import { render } from "react-dom";
import MaterialTable from "material-table";
import SaveAltIcon from "#material-ui/icons/SaveAlt";
import tableIcons from "./TableIcons.js";
const rando = max => Math.floor(Math.random() * max);
const rawData = [
{ id: 1111111111, archive: "true", type: "CC" },
{ id: 2222222222, archive: "", type: "RR" },
{ id: 3333333333, archive: "true", type: "CC" },
{ id: 4444444444, archive: "", type: "PS" },
{ id: 5555555555, archive: "true", type: "II" }
];
const columns = [
{ title: "Id", field: "id" },
{ title: "Type", field: "type" },
{ title: "Status", field: "archive", type: "boolean" }
];
const App = () => {
const [data, setData] = useState(rawData);
return (
<MaterialTable
data={data}
columns={columns}
title="Starter Template"
icons={tableIcons}
/>
);
};
render(<App />, document.querySelector("#root"));
https://codesandbox.io/s/material-table-starter-template-0s0np?file=/src/index.js
First of all I modified the archive prop value from "true" to true in order to make conditional checks easier, this way the type is boolean instead of string.
Then I imported Check and Remove icons from the depency you were already using:
import { Check, Remove } from "#material-ui/icons";
And finally where the columns const is defined, I pass a function to the render prop, like this:
render: rowdata => rowdata.archive !== true ? <Check /> : <Remove />
Ofcourse you can change the conditional if needed. Link to the Material-Table documentation on this topic here.
This is your code after the modifications:
import React, { useState } from "react";
import { render } from "react-dom";
import MaterialTable from "material-table";
import SaveAltIcon from "#material-ui/icons/SaveAlt";
import tableIcons from "./TableIcons.js";
import { Check, Remove } from "#material-ui/icons";
const rando = (max) => Math.floor(Math.random() * max);
const rawData = [
{ id: 1111111111, archive: true, type: "CC" },
{ id: 2222222222, archive: "", type: "RR" },
{ id: 3333333333, archive: true, type: "CC" },
{ id: 4444444444, archive: "", type: "PS" },
{ id: 5555555555, archive: true, type: "II" },
];
const columns = [
{ title: "Id", field: "id" },
{ title: "Type", field: "type" },
{
title: "Status",
field: "archive",
type: "boolean",
render: (rowdata) => (rowdata.archive !== true ? <Check /> : <Remove />),
// the ternary expression above is the same as:
// if (rowdata.archive !== true) {
// return <Check />;
// } else {
// return <Remove />;
// }
},
//
];
const App = () => {
const [data, setData] = useState(rawData);
return (
<MaterialTable
data={data}
columns={columns}
title="Starter Template"
icons={tableIcons}
/>
);
};
render(<App />, document.querySelector("#root"));
Here is the link to the sandbox. I hope this works for you!

How to prevent rows adjustment after they are expanded?

I am working with antd table and antd transfer component and I am facing a small challenge with CSS.
I have created a small example with codesandbox. If I try to expand a row, you will see that other columns try to adjust themselves. Is there a way I could prevent this? I do not want the rows to adjust themselves. The table should feel the same after the expansion as it was before the expansion.
This is code from the sandbox link I shared above that generates the table.
import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Transfer, Table, Tag } from "antd";
function difference(listOne, listTwo) {
const set1 = new Set(listOne);
const set2 = new Set(listTwo);
const difference = new Set([...set1].filter(x => !set2.has(x)));
return Array.from(difference);
}
// Customize Table Transfer
const TableTransfer = ({ leftColumns, rightColumns, ...restProps }) => (
<Transfer {...restProps}>
{({
direction,
filteredItems,
onItemSelectAll,
onItemSelect,
selectedKeys: listSelectedKeys,
disabled: listDisabled
}) => {
const columns = direction === "left" ? leftColumns : rightColumns;
const rowSelection = {
getCheckboxProps: item => ({ disabled: listDisabled || item.disabled }),
onSelectAll(selected, selectedRows) {
const treeSelectedKeys = selectedRows
.filter(item => !item.disabled)
.map(({ key }) => key);
const diffKeys = selected
? difference(treeSelectedKeys, listSelectedKeys)
: difference(listSelectedKeys, treeSelectedKeys);
onItemSelectAll(diffKeys, selected);
},
onSelect({ key }, selected) {
onItemSelect(key, selected);
},
selectedRowKeys: listSelectedKeys
};
return (
<Table
rowSelection={rowSelection}
columns={columns}
dataSource={filteredItems}
size="small"
/>
);
}}
</Transfer>
);
const mockTags = ["eg", "gg", "e"];
const mockData = [];
for (let i = 0; i < 20; i++) {
let data = {
key: i.toString(),
title: `eq${i + 1}`,
description: `description of eq${i + 1}`,
disabled: false, //i % 4 === 0,
tag: mockTags[i % 3]
};
if (i % 2 === 0) {
const children = [
{
key: i.toString() + "children",
title: `children-${i + 1}`,
description: `children description-${i + 1}`,
disabled: true,
tag: "tag"
}
];
data["children"] = children;
}
mockData.push(data);
}
const originTargetKeys = mockData
.filter(item => +item.key % 3 > 1)
.map(item => item.key);
const leftTableColumns = [
{
dataIndex: "title",
title: "Name"
},
{
dataIndex: "tag",
title: "Tag",
render: tag => <Tag>{tag}</Tag>
},
{
dataIndex: "description",
title: "Description"
}
];
const rightTableColumns = [
{
dataIndex: "title",
title: "Names"
},
{
dataIndex: "tag",
title: "Tag",
render: tag => <Tag>{tag}</Tag>
},
{
dataIndex: "description",
title: "Description"
}
];
class App extends React.Component {
state = {
targetKeys: originTargetKeys
};
onChange = nextTargetKeys => {
this.setState({ targetKeys: nextTargetKeys });
};
render() {
const { targetKeys, disabled } = this.state;
return (
<div>
<TableTransfer
className="table-transfer"
dataSource={mockData}
titles={[
<div>
<input type="checkbox" checked />
Equipment <input type="checkbox" checked /> Groups
</div>,
<div>
<input type="checkbox" checked />
Equipment <input type="checkbox" checked /> Groups
</div>
]}
targetKeys={targetKeys}
disabled={disabled}
showSearch={true}
onChange={this.onChange}
filterOption={(inputValue, item) =>
item.title.indexOf(inputValue) !== -1 ||
item.tag.indexOf(inputValue) !== -1
}
leftColumns={leftTableColumns}
rightColumns={rightTableColumns}
locale={{
itemUnit: "Equipment",
itemsUnit: "Equipments",
notFoundContent: "The list is empty",
searchPlaceholder: "Search here"
}}
/>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("container"));
You want to constraint your columns width, for example, try this on the leftTableColumns and notice the difference with the right one:
const leftTableColumns = [
{
dataIndex: 'title',
title: 'Name',
width: '45%'
},
{
dataIndex: 'tag',
title: 'Tag',
render: tag => <Tag>{tag}</Tag>,
width: '10%'
},
{
dataIndex: 'description',
title: 'Description',
width: '40%'
}
];
Refer to Table Column API.
Fork of your codebox:

Categories