Antd table sorting ignores children - reactjs

I am trying to sort a table that has children, but it ignores the value "Age" of the children. All items including children should sort in Ascending or descending order. Not sure if this is a bug or my implementation is incorrect.
Codesanbox: https://codesandbox.io/s/hardcore-paper-nvodp
Current Result, Children are ignored. The idea is too sort every item in the tree.
js:
const columns = [
{
title: "Name",
dataIndex: "name",
key: "name"
},
{
title: "Age",
dataIndex: "age",
key: "age",
width: "12%",
sorter: {
compare: (a, b) => a.age - b.age,
multiple: 3
}
},
{
title: "Address",
dataIndex: "address",
width: "30%",
key: "address"
}
];
const data = [
{
key: 1,
name: "John Brown sr.",
age: 60,
address: "New York No. 1 Lake Park",
children: [
{
key: 11,
name: "John Brown",
age: 42,
address: "New York No. 2 Lake Park"
}
]
},
{
key: 2,
name: "Joe Black",
age: 22,
address: "Sidney No. 1 Lake Park",
children: [
{
key: 10,
name: "John Brown",
age: 12,
address: "New York No. 2 Lake Park"
}
]
}
];
function onChange(pagination, filters, sorter, extra) {
console.log("params", extra);
}
function TreeData() {
return (
<>
<Table
columns={columns}
dataSource={data}
onChange={onChange}
indentSize={0}
/>
</>
);
}

You can not resort parent and children in the same tree, so that all elements are sorted by age.
This wouldn't be a tree any longer and does not make sense at all. You would lost the parent - child relation.
If you want to sort all elements by age, you have to move the items into a list and sort them there.
You can only sort the items at the same level and that is what #edo9k 's implementation does correctly!
Tree sorting works as expected by age at for every tree level:
parents [22, 61, 62]
children1 [12]
children2 [10, 30, 40]
children3
[41, 42]

Best way you can achieve this through AntD is by using the Nested Tables component. You can display your expandable/children data for each row in your main table into this nested table and then by incorporating the sortable functions in your nested table you can sort that data.

Related

Search item in multidimensional array

I'm working with a tree nodes and I want to create a function to find an item by its ID.
What is the best and optimal solution to get it?
I think it will be a recursive function, but I'm not sure and I want a help please to choose what I will use to resolve this issue :)
This is my example:
const treeData = [
{
title: 'parent 1',
key: 11,
children: [
{
title: 'parent 1-0',
key: 12,
children: [
{
title: 'leaf',
key: 13,
children: [
{
title: 'leaf111',
key: 14,
},
{
title: 'leaf',
key: 15,
},
],
},
{
title: 'leaf666',
key:88,
},
],
},
{
title: 'parent 1-1',
key: 55,
children: [
{
title: (
<span
style={{
color: '#1890ff',
}}
>
sss
</span>
),
key: '0-0-1-0',
},
],
},
],
},
];
Input : 14
Output : {title: 'leaf111',key: 14},
We can create a rerusive function that:
Loops though each object in the array and
Returns the object if id matches
Calls itself with the objects children
const treeData = [{title: 'parent 1', key: 11, children: [{title: 'parent 1-0', key: 12, children: [{title: 'leaf', key: 13, children: [{title: 'leaf111', key: 14, }, {title: 'leaf', key: 15, }, ], }, {title: 'leaf666', key:88, }, ], }, {title: 'parent 1-1', key: 55, children: [{title: '(<span style={{color: \'#1890ff\', }} > sss </span> )', key: '0-0-1-0', }, ], }, ], }, ];
const findById = (e, id) => {
for (let o of e) {
return (o.key == id) ? o : findById(o.children, id);
}
}
const res = findById(treeData, 14);
console.log(res);
Output:
{
"title": "leaf111",
"key": 14
}
You can use a tree walker, which traverses the tree and calls a provided function upon visiting each node. The provided function could check to see if the node matches the provided ID.
An example:
function getNodeById(id) {
let matchingNode;
walk(tree, node => {
if(node.key === 14) {
matchingNode = node;
}
});
return matchingNode;
}
A tree walker can be implemented using recursion, as you mention. In a preorder operation, which starts at the topmost node, the walker takes the tree (the root node) and on each invocation:
calls the callback function with the current node
for each child node, calls itself with the child node and callback
function walker(node, cb) {
cb(node);
if (Array.isArray(node.children)) {
node.children.forEach(child => walker(child, cb));
}
}
For use with React, you can implement your own walking using React.Children.forEach, or you may prefer try a library like https://github.com/FormidableLabs/react-ssr-prepass.

How can we disable antd table's checkboxes based on condition?

For example there are n no of records I want to enable only selected checboxed reamining all records should be disabled automatically?
please check this below my getCheckboxProps() function check is wrong unable to solve it
Sandbox link
I wanted to disable all non selected checkboxes and here I have no of checboxes can be enabled length we should not cross that length.In my case remaining_total variable.Can anyone help me in right direction?
Your provided link was broken, however one way to disabled all the checkbox in antd table row is to return {disabled: true} on getCheckboxProps function on each cycle. If you have a unique key or item, you can use that to disable specific row, just return {disabled: true} if meet a condition. Here's sample on enabling the first two rows checkbox:
const data = [
{
key: "1",
name: "John Brown",
age: 32,
address: "New York No. 1 Lake Park"
},
{
key: "2",
name: "Jim Green",
age: 42,
address: "London No. 1 Lake Park"
},
{
key: "3",
name: "Joe Black",
age: 32,
address: "Sidney No. 1 Lake Park"
},
{
key: "4",
name: "Bon Jov",
age: 99,
address: "Sidney No. 1 Lake Park"
},
{
key: "5",
name: "User 5",
age: 99,
address: "Sidney No. 1 Lake Park"
},
{
key: "6",
name: "User 6",
age: 99,
address: "Sidney No. 1 Lake Park"
}
];
const rowSelection = {
getCheckboxProps: (record) => {
const rowIndex = data.findIndex((item) => item.key === record.key);
return {
disabled: rowIndex > 1 //enable first 2 rows only
};
}
};
Here is a sample of disabling the first 4 rows:
const rowSelection = {
getCheckboxProps: (record) => {
const rowIndex = data.findIndex((item) => item.key === record.key);
return {
disabled: rowIndex < 4 //disable the first 4 rows only
};
}
};
Here's a working sample:

React ant design table cell collapse issue

Im using my react type script project for ant design table
i want to know how to do that following image like as table, im search any tutorial but not seen anything, any one know how to do that correctly.
code sand box here
Thanks
image here
code here
class App extends React.Component {
columns: any = [
{
title: "Name",
dataIndex: "name",
key: "name"
},
{
title: "Age",
dataIndex: "age",
key: "age"
},
{
title: "Address",
dataIndex: "address",
key: "address"
},
{
title: "Tags",
key: "tags",
dataIndex: "tags"
},
{
title: "Action",
key: "action"
}
];
data: any = [
{
key: "1",
name: "John Brown",
age: 32,
address: "New York No. 1 Lake Park",
tags: ["nice", "developer"]
},
{
key: "2",
name: "Jim Green",
age: 42,
address: "London No. 1 Lake Park",
tags: ["loser"]
},
{
key: "3",
name: "Joe Black",
age: 32,
address: "Sidney No. 1 Lake Park",
tags: ["cool", "teacher"]
}
];
render() {
return <Table columns={this.columns} dataSource={this.data} />;
}
}
You want to create 2 sub rows in each row, but only for some columns. you can use rowspan for this.
you can duplicate your rows (row1-row1-row2-row2-row3-row3-...), and put the subrow values in them (row1_subrow1-row1_subrow2-row2_subrow1-row2_subrow2-...), then use rowspan for the columns you want to expand (like Section and Name in your image), and expand the odd rows and collapse the even rows for this columns.
the full code : (Codesandbox Demo)
import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Table } from "antd";
let multiRowRender = (value, row, index) => {
const obj = {
children: value,
props: {}
};
if (index % 2 === 0) {
obj.props.rowSpan = 2;
}
if (index % 2 === 1) {
obj.props.rowSpan = 0;
}
return obj;
};
const columns = [
{
title: "Number",
dataIndex: "number"
},
{
title: "Issue",
dataIndex: "issue"
},
{
title: "Name",
dataIndex: "name",
render: multiRowRender
},
{
title: "Section",
dataIndex: "section",
render: multiRowRender
}
];
let data = [
{
key: "1",
name: "John Brown",
issues: [32, 100],
numbers: [18889898989, 545054],
section: "sec 1"
},
{
key: "2",
name: "Jim Green",
issues: [42, 50],
numbers: [18889898888, 1420054],
section: "sec 2"
}
];
let data2 = [];
data.forEach(d => {
data2.push({ ...d, issue: d.issues[0], number: d.numbers[0] });
data2.push({
...d,
issue: d.issues[1],
number: d.numbers[1],
key: d.key + "-row2"
});
});
data = data2;
ReactDOM.render(
<Table columns={columns} dataSource={data} bordered />,
document.getElementById("container")
);
Codesandbox Demo

Units for specifying width (of a table column) in Antd?

We are using the latest stable version 2 of Antd (and cannot make the jump to version 3 due to version dependency constraints). How do we specify the width of my table columns, ideally to the length of the text in title property? According to the official table component docu, there is the obvious property width for a column. All the documentation says in English is
Property: width
Description: Width of this column
Type: string|number
Default: -
1st part of the question: If I specify only a number, what unit is used? I tried different things, but it does not really look like it is dp as described e.g at What is the default unit for width, height, padding etc in React Native for iOS?
2nd part: If I specify a string, which units can I use? I tried ex, em, and px and none of them seems to work.
The 3rd part of the question: Maybe we overlooked a property of the table tag which overwrites or limits the usage of width is a column?
Any input is appreciated, already the translation of the original documentation to English would help. Or explaining the a related Github issue: 'how to set table columns width? the width property is invalid'.
Thanks for your time in advance - a puzzled Antd newbie.
From the antd official document:
import { Table } from 'antd';
const columns = [{
title: 'Name',
dataIndex: 'name',
key: 'name',
width: '40%',
}, {
title: 'Age',
dataIndex: 'age',
key: 'age',
width: '30%',
}, {
title: 'Address',
dataIndex: 'address',
key: 'address',
}];
const data = [{
key: 1,
name: 'John Brown sr.',
age: 60,
address: 'New York No. 1 Lake Park',
children: [{
key: 11,
name: 'John Brown',
age: 42,
address: 'New York No. 2 Lake Park',
}, {
key: 12,
name: 'John Brown jr.',
age: 30,
address: 'New York No. 3 Lake Park',
children: [{
key: 121,
name: 'Jimmy Brown',
age: 16,
address: 'New York No. 3 Lake Park',
}],
}, {
key: 13,
name: 'Jim Green sr.',
age: 72,
address: 'London No. 1 Lake Park',
children: [{
key: 131,
name: 'Jim Green',
age: 42,
address: 'London No. 2 Lake Park',
children: [{
key: 1311,
name: 'Jim Green jr.',
age: 25,
address: 'London No. 3 Lake Park',
}, {
key: 1312,
name: 'Jimmy Green sr.',
age: 18,
address: 'London No. 4 Lake Park',
}],
}],
}],
}, {
key: 2,
name: 'Joe Black',
age: 32,
address: 'Sidney No. 1 Lake Park',
}];
// rowSelection objects indicates the need for row selection
const rowSelection = {
onChange: (selectedRowKeys, selectedRows) => {
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
},
onSelect: (record, selected, selectedRows) => {
console.log(record, selected, selectedRows);
},
onSelectAll: (selected, selectedRows, changeRows) => {
console.log(selected, selectedRows, changeRows);
},
};
ReactDOM.render(
<Table columns={columns} rowSelection={rowSelection} dataSource={data} />
, mountNode);

ant design table with dynamic children columns

I'm using ant's table and trying to setup dynamic columns.
What I need is a table that shows a list of users with their performance for each of the classes as in the example below.
Details: I have a grouped column Performance that can have different sub-columns (current example shows columns science and physics). I'm calling renderContent() which sets up an object that has property children. I found this "solution" from ant's example here. The problem is that ant's example outputs children prop type string, while my function outputs prop type array. Which results in the error.
Here is a link to sandbox:
https://codesandbox.io/embed/ecstatic-cookies-4nvci?fontsize=14
Note: if you uncomment children array in columns [line 46-59], you will see what my expected result should be.
The render method shouldn't return the object with children array. To use the render method, you would have to return a valid React component (or simply HTML tag ---like span).
However in your case, I prefer we extract subjects before passing it into the table and then generate children array dynamically. Something like below:
const renderContent = (value, row, index) => {
return setupPerformance(value)
};
const setupPerformance = performance => {
return performance.map(p => {
const { id, title, percentage } = p;
return <span>{percentage}%</span>
});
};
const data = [
{
key: 0,
firstName: "John",
lastName: "Smith",
performance: [
{
id: 1,
title: "science",
percentage: 75
},
{
id: 2,
title: "physics",
percentage: 36
}
]
},
{
key: 1,
firstName: "Ann",
lastName: "Smith",
performance: [
{
id: 1,
title: "science",
percentage: 68,
timeSpent: 50,
completionDate: "2019-02-07"
},
{
id: 2,
title: "physics",
percentage: 100
}
]
}
];
let subjects = data[0].performance
const columns = [
{
title: "Full Name",
children: [
{
title: "firstName",
dataIndex: "firstName",
key: "firstName"
},
{
title: "lastName",
dataIndex: "lastName",
key: "lastName"
}
]
},
{
title: "Performance",
dataIndex: "performance",
children:
subjects.map(e => {
return {
title: e.title,
dataIndex: "performance["+(e.id-1)+"].percentage",
key: "key-"+e.id,
render: value => <span>{value}%</span>
}
})
}
];
Because of the solution in answer from Mobeen does not work anymore, I have tried to solve this.
I have extended the render method for the children columns of performance column:
...
{
title: "Performance",
dataIndex: "performance",
children: subjects.map((assessment) => {
const { title, id } = assessment;
return {
title,
dataIndex: "performance",
key: id,
render: (values) =>
values.map((value, index) => {
let ret;
if (index === id - 1) ret = values[index].percentage + "%";
return ret;
})
};
})
}
...
It returns only the percentage value of the subject with the corresponding id.
It is not very clean, but it works.
Check the solution in sandbox: https://codesandbox.io/s/prod-lake-7n6zgj

Resources