How to sort strings in React JS - reactjs

I have a table from Ant Design where i want to sort a column. This column is name.
const data = [
{
key: "1",
name: "John Brown",
age: 32,
address: "New York No. 1 Lake Park"
},
{
key: "2",
name: "Carl 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: "Jim Red",
age: 32,
address: "London No. 2 Lake Park"
}
];
class App extends React.Component {
state = {
filteredInfo: null,
sortedInfo: null
};
handleChange = (pagination, filters, sorter) => {
console.log("Various parameters", pagination, filters, sorter);
this.setState({
filteredInfo: filters,
sortedInfo: sorter
});
};
clearFilters = () => {
this.setState({ filteredInfo: null });
};
clearAll = () => {
this.setState({
filteredInfo: null,
sortedInfo: null
});
};
setAgeSort = () => {
this.setState({
sortedInfo: {
order: "descend",
columnKey: "age"
}
});
};
render() {
let { sortedInfo } = this.state;
sortedInfo = sortedInfo || {};
const columns = [
{
title: "Name",
dataIndex: "name",
key: "name",
sorter: (a, b) => a.name.length - b.name.length,
sortOrder: sortedInfo.columnKey === "name" && sortedInfo.order,
ellipsis: true
},
{
title: "Age",
dataIndex: "age",
key: "age",
sorter: (a, b) => a.age - b.age,
sortOrder: sortedInfo.columnKey === "age" && sortedInfo.order,
ellipsis: true
},
{
title: "Address",
dataIndex: "address",
key: "address",
sorter: (a, b) => a.address.length - b.address.length,
sortOrder: sortedInfo.columnKey === "address" && sortedInfo.order,
ellipsis: true
}
];
return (
<>
<Table
columns={columns}
dataSource={data}
onChange={this.handleChange}
/>
</>
);
}
}
Now, when i sort in ascending order the data does not order in the right way. Why? And how to solve?
demo: https://codesandbox.io/s/reset-filters-and-sorters-antd494-forked-m3ljo?file=/index.js:143-2169

Your sort compare function is comparing the length of name which will sort the array by the length of the name.
Change your sorter for name to below.
sorter: (a, b) => {
if(a.name < b.name) { return -1; }
if(a.name > b.name) { return 1; }
return 0;
},
You also need to change sorter for address.
sorter: (a, b) => {
if(a.address < b.address) { return -1; }
if(a.address > b.address) { return 1; }
return 0;
},

Try this sorter function for name:
sorter: (a, b) => a.name.toUpperCase().localeCompare(b.name.toUpperCase())

I've Tried this code on your snippet and it is working good -
import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Table } from "antd";
const data = [
{
key: "1",
name: "John Brown",
age: 32,
address: "New York No. 1 Lake Park"
},
{
key: "2",
name: "Carl 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: "Jim Red",
age: 32,
address: "London No. 2 Lake Park"
}
];
class App extends React.Component {
state = {
filteredInfo: null,
sortedInfo: null
};
handleChange = (pagination, filters, sorter) => {
console.log("Various parameters", pagination, filters, sorter);
this.setState({
filteredInfo: filters,
sortedInfo: sorter
});
};
clearFilters = () => {
this.setState({ filteredInfo: null });
};
clearAll = () => {
this.setState({
filteredInfo: null,
sortedInfo: null
});
};
setAgeSort = () => {
this.setState({
sortedInfo: {
order: "descend",
columnKey: "age"
}
});
};
render() {
let { sortedInfo } = this.state;
sortedInfo = sortedInfo || {};
const columns = [
{
title: "Name",
dataIndex: "name",
key: "name",
sorter: (a,b) => (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0),
sortOrder: sortedInfo.columnKey === "name" && sortedInfo.order,
ellipsis: true
},
{
title: "Age",
dataIndex: "age",
key: "age",
sorter: (a, b) => a.age - b.age,
sortOrder: sortedInfo.columnKey === "age" && sortedInfo.order,
ellipsis: true
},
{
title: "Address",
dataIndex: "address",
key: "address",
sorter: (a,b) => (a.address > b.address) ? 1 : ((b.address > a.address) ? -1 : 0),
sortOrder: sortedInfo.columnKey === "address" && sortedInfo.order,
ellipsis: true
}
];
return (
<>
<Table
columns={columns}
dataSource={data}
onChange={this.handleChange}
/>
</>
);
}
}
ReactDOM.render(<App />, document.getElementById("container"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Related

How can i use react-drag-listview with functional components to make draggable columns with antd-table?

I'm trying to create a draggable table with antd, but i always use functionalcomponents in react and all the examples and doc that i found in internet is using class components and that=this stufs like. I don't know how can i use react-drag-listview library with the functional components.
this.state = {
columns: [
{
title: <span className="dragHandler">Key</span>,
dataIndex: "key",
render: (text) => <span>{text}</span>,
width: 50
},
{
title: <span className="dragHandler">Name</span>,
dataIndex: "name",
width: 200
},
{
title: <span className="dragHandler">Gender</span>,
dataIndex: "gender",
width: 100
},
{
title: <span className="dragHandler">Age</span>,
dataIndex: "age",
width: 100
},
{
title: <span className="dragHandler">Address</span>,
dataIndex: "address"
}
]
};
const that = this;
this.dragProps = {
onDragEnd(fromIndex, toIndex) {
const columns = [...that.state.columns];
const item = columns.splice(fromIndex, 1)[0];
columns.splice(toIndex, 0, item);
that.setState({
columns
});
},
nodeSelector: "th",
handleSelector: ".dragHandler",
ignoreSelector: "react-resizable-handle"
};
}
This a small piece of code that I'm trying to copy from, but i don't understand it.
Even an exaple of any small code where i can see how to use with functional components it may work for me.
Tis is the url of the example above: https://codesandbox.io/s/table-column-sortable-resizable-st9bt?file=/index.js
React Drag List View Using Functional Component
import "./index.css";
import { useState } from "react";
import { Resizable } from "react-resizable";
import { Table } from "antd";
import ReactDragListView from "react-drag-listview";
const ResizableTitle = (props) => {
const { onResize, width, ...restProps } = props;
if (!width) {
return <th {...restProps} />;
}
return (
<Resizable
width={width}
height={0}
handle={
<span
className='react-resizable-handle'
onClick={(e) => {
e.stopPropagation();
}}
/>
}
onResize={onResize}
draggableOpts={{ enableUserSelectHack: false }}
>
<th {...restProps} />
</Resizable>
);
};
const data = [
{ key: "1", name: "Boran", gender: "male", age: "12", address: "New York" },
{ key: "2", name: "JayChou", gender: "male", age: "38", address: "TaiWan" },
{ key: "3", name: "Lee", gender: "female", age: "22", address: "BeiJing" },
{ key: "4", name: "ChouTan", gender: "male", age: "31", address: "HangZhou" },
{ key: "5", name: "AiTing", gender: "female", age: "22", address: "Xi’An" },
];
const components = { header: { cell: ResizableTitle } };
const App = () => {
const [columns, setColumns] = useState([
{
title: <span className='dragHandler'>Key</span>,
dataIndex: "key",
render: (text) => <span>{text}</span>,
width: 50,
},
{
title: <span className='dragHandler'>Name</span>,
dataIndex: "name",
width: 200,
},
{
title: <span className='dragHandler'>Gender</span>,
dataIndex: "gender",
width: 100,
},
{
title: <span className='dragHandler'>Age</span>,
dataIndex: "age",
width: 100,
},
{
title: <span className='dragHandler'>Address</span>,
dataIndex: "address",
},
]);
const onDragEnd = (fromIndex, toIndex) => {
setColumns((prev) => {
const nextColumns = [...prev];
const item = nextColumns.splice(fromIndex, 1)[0];
nextColumns.splice(toIndex, 0, item);
return nextColumns;
});
};
const handleResize = (size, index) => {
setColumns((prev) => {
const nextColumns = [...prev];
nextColumns[index] = {
...nextColumns[index],
width: size.width,
};
return nextColumns;
});
};
const tableColumns = columns.map((col, index) => ({
...col,
onHeaderCell: (column) => ({
width: column.width,
onResize: (e, { size }) => handleResize(size, index),
}),
}));
return (
<ReactDragListView.DragColumn
onDragEnd={onDragEnd}
nodeSelector='th'
handleSelector='.dragHandler'
ignoreSelector='react-resizable-handle'
>
<Table bordered columns={tableColumns} dataSource={data} components={components} />
</ReactDragListView.DragColumn>
);
};
export default App;

Data is not showing in Grid Lookup React.js MaterialUI

I need to show my lookup like this
Lookup image what I want
So the code for this lookup is which is shown is hardcoded but i want to do retrieve data dynamically.
Hardcoded data
I had done with to retrieve data from database and the data is also in same format when i console log the both they are same.
AvaibleMechanic is which we retrieve from DB and dyanmicMechanicLookUp is harcoded
Both data console log SS
setColumnsCode
const [columns, setColumns] = useState([
{ title: "OrderId", field: "_id", editable: "never" },
{ title: "Customer Name", field: "customerName", editable: "never" },
{ title: "Car Name", field: "carName", editable: "never" },
{ title: "Car Number", field: "carNumber", editable: "never" },
{ title: "Address", field: "custAddress", editable: "never" },
{ title: "Service Name", field: "serviceName", editable: "never" },
{ title: "Price", field: "servicePrice", editable: "never" },
{
title: "Assign Mechanic",
field: "mechanicId",
lookup: AvailableMechanic,
},
]);
when i want to see data which is retrieve from Database is not show on the lookup is look like this
Retrieve from database lookup SS
You can see when I used dynamicLookUp which is hardcoded it works fine but when i used data which is retrieve it's not shown on the grid
FullCode
import React, { useState, useEffect } from "react";
import AdminOrders from "../../../services/member/orders.js/admin_orders";
import MechanicService from "../../../services/member/Mechanic/Mechanic_Services";
import "./CSS/Cars.css";
import MaterialTable from "material-table";
import { useSnackbar } from "notistack";
function Orders() {
const [orders, setOrders] = useState([]);
const [completedOrders, setCompletedOrders] = useState([]);
const [AvailableMechanic, setAvailableMechanic] = useState({});
const { enqueueSnackbar, closeSnackbar } = useSnackbar();
//for error handling
const [iserror, setIserror] = useState(false);
const [errorMessages, setErrorMessages] = useState([]);
const getAvailableMechanics = async () => {
await MechanicService.findAvailable()
.then((res) => {
res.map((key,i) => {
setAvailableMechanic(prevState => ({
...prevState,
[key._id]: key.name
}))
})
})
.catch((err) => {
console.log(err)
})
}
const getPlacedOrders = () => {
AdminOrders.findPlacedOrders()
.then((response) => {
setOrders(response);
})
.catch((err) => {
console.log(err);
});
};
const getCompletedOrders = () => {
AdminOrders.findCompletedOrders()
.then((res) => {
setCompletedOrders(res);
})
.catch((err) => {
console.log(err);
});
};
useEffect(() => {
getAvailableMechanics();
getPlacedOrders();
getCompletedOrders();
}, []);
const dynamicMechanicsLookUp = {
'621d06355e364ae391f59af4': "John Doe 1",
'621e3fb9d99ae5efd754b5d6': "John Doe 2",
'62766409db9ad573da5655cc': "John Doe 3",
'6276642cdb9ad573da5655d1': "John Doe 4",
'62766433db9ad573da5655d4': "John Doe 5",
};
// const dynamicMechanicsLookUp = AvailableMechanic;
console.log("dynamicLookUp",dynamicMechanicsLookUp)
console.log("AvailableMechanic",AvailableMechanic)
const [columns, setColumns] = useState([
{ title: "OrderId", field: "_id", editable: "never" },
{ title: "Customer Name", field: "customerName", editable: "never" },
{ title: "Car Name", field: "carName", editable: "never" },
{ title: "Car Number", field: "carNumber", editable: "never" },
{ title: "Address", field: "custAddress", editable: "never" },
{ title: "Service Name", field: "serviceName", editable: "never" },
{ title: "Price", field: "servicePrice", editable: "never" },
{
title: "Assign Mechanic",
field: "mechanicId",
lookup: AvailableMechanic,
},
]);
const [column, setColumn] = useState([
{ title: "OrderId", field: "_id" },
{ title: "Customer Name", field: "customerName" },
{ title: "Car Name", field: "carName" },
{ title: "Car Number", field: "carNumber" },
{ title: "Address", field: "custAddress" },
{ title: "Service Name", field: "serviceName" },
{ title: "Price", field: "servicePrice" },
{ title: "Assigned Mechanic", field: "mechanicId" },
]);
const handleRowUpdate = (newData, oldData, resolve) => {
let errorList = [];
if (errorList.length < 1) {
AdminOrders.assignOrder(newData._id, newData.mechanicId)
.then((res) => {
const dataUpdate = [...orders];
const index = oldData.tableData.id;
dataUpdate[index] = newData;
setOrders([...dataUpdate]);
resolve();
setIserror(false);
setErrorMessages([]);
enqueueSnackbar(res, {
variant: "success",
});
})
.catch((error) => {
setErrorMessages(["Update failed! Server error"]);
setIserror(true);
resolve();
});
} else {
setErrorMessages(errorList);
setIserror(true);
resolve();
}
};
const [display, setdisplay] = useState(false);
const openTable = () => {
setdisplay(true);
};
const closeTable = () => {
setdisplay(false);
};
return (
<div className="cars_container">
<br />
<button onClick={openTable}>See Completed Orders</button>
<br />
{orders ? (
<MaterialTable
title="CURRENT ORDERS DATA"
columns={columns}
data={orders}
editable={{
onRowUpdate: (newData, oldData) =>
new Promise((resolve, reject) => {
handleRowUpdate(newData, oldData, resolve);
}),
}}
options={{
headerStyle: {
backgroundColor: "#01579b",
color: "#FFF",
},
exportButton: true,
}}
/>
) : (
<div>
<br />
<h2>NO CURRENT ORDERS RIGHT NOW</h2>
</div>
)}
<br />
<br />
<br />
{display ? (
<div>
<h1>COMPLETED ORDERS</h1>
<MaterialTable
title="CURRENT ORDERS DATA"
columns={column}
data={completedOrders}
options={{
headerStyle: {
backgroundColor: "#01579b",
color: "#FFF",
},
exportButton: true,
}}
/>
<br />
<button onClick={closeTable}>Close Table</button>
<br />
<br />
<br />
</div>
) : null}
</div>
);
}
export default Orders;
Sorry for the bad english. Please if you find any mistake i am making please let me know
Thanks

Ant design 4 table loading not working properly

Im using my react project for ant design 4, i added table loading for loading, I have some conflict added loaded not working, anyone know how to fix that issue?
Thanks
code here
Here the stackblitz
const columns = [
{
title: "Name",
dataIndex: "name",
key: "name",
render: text => {text}
},
{
title: "Age",
dataIndex: "age",
key: "age"
},
{
title: "Address",
dataIndex: "address",
key: "address"
},
{
title: "Tags",
key: "tags",
dataIndex: "tags",
render: tags => (
<span>
{tags.map(tag => {
let color = tag.length > 5 ? "geekblue" : "green";
if (tag === "loser") {
color = "volcano";
}
return (
<Tag color={color} key={tag}>
{tag.toUpperCase()}
</Tag>
);
})}
</span>
)
},
{
title: "Action",
key: "action",
render: (text, record) => (
<span>
Invite {record.name}
<Divider type="vertical" />
Delete
</span>
)
}
];
class App extends React.Component {
state = {
data: [],
pagination: {
current: 1,
pageSize: 10
},
loading: true
};
componentDidMount() {
setTimeout(() => {
this.setState({ loading: false });
}, 1000);
}
render() {
const data = [
{
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"]
}
];
return (
<Table
columns={columns}
dataSource={data}
loading={this.state.loading}
onChange={this.handleTableChange}
/>
);
}
}
ReactDOM.render(<App />, document.getElementById("container"));

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

Select child rows when we select on the parent row using rowSelection in antd table

I'm trying rowselection reactjs using antd table.I'm trying this one
ant-components-table-demo-expand-children
when I select parent row it must select child rows of that parent (it should tick mark the child rows).
this.rowSelection = {
onSelect: (record, selected, selectedRows) => this.onSelectChange(record, selected, selectedRows),
onSelectAll: (selected, selectedRows, changeRows) => this.allRowsSelected(selected, selectedRows, changeRows)
};
<Table
rowKey={data._id}
columns={this.columns1}
rowSelection={this.rowSelection}
expandedRowRender={(record, index, indent, expanded) =>
this.expanding(record, expanded)
}
onExpand={this.onExpand}
dataSource={data}
/>
When you select a parent node, you can get the children nodes from onSelect function. Similarly, You can get all the nodes when you select/deselect from onSelectAll function.
You need to store those keys of selected parent node and it's children nodes in state.
To select/deselect checkboxes, you need to set/unset those keys to selectedRowKeys like so: selectedRowKeys: Array.from(selectedCBKeys) (selectedCBKeys = parent key + it's children keys)
const rowSelection = {
selectedRowKeys: Array.from(selectedCBKeys),
onChange: (selectedRowKeys, selectedRows) => {},
onSelect: (record, selected, selectedRows) => {
this.getKey(record);
},
onSelectAll: (selected, selectedRows, changeRows) => {
changeRows.map(item => this.getKey(item));
}
};
How to get all the keys of children nodes of a parent tree?
Just recursively traverse the parent tree. I collected all the keys like so:
getKey = data => {
this.storeKey(data.key); //it just stores the key in "state"
if (data.children) {
data.children.map(item => this.getKey(item));
}
};
This is how I stored all the keys. I used Set.
state = {
selectedCBKeys: new Set()
};
storeKey = key => {
//If the key is already present in "state" just delete it.
//It helps in toggling the checkboxes.. right?
if (this.state.selectedCBKeys.has(key)) {
const newSet = this.state.selectedCBKeys;
newSet.delete(key);
this.setState({
selectedCBKeys: newSet
});
return;
}
this.setState(prevState => ({
...prevState,
selectedCBKeys: prevState.selectedCBKeys.add(key)
}));
};
App.js
import { Table } from "antd";
const columns = [
{
title: "Name",
dataIndex: "name",
key: "name"
},
{
title: "Age",
dataIndex: "age",
key: "age",
width: "12%"
},
{
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: 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: 2,
name: "Joe Black",
age: 32,
address: "Sidney No. 1 Lake Park"
}
];
class App extends Component {
state = {
selectedCBKeys: new Set()
};
storeKey = key => {
if (this.state.selectedCBKeys.has(key)) {
const newSet = this.state.selectedCBKeys;
newSet.delete(key);
this.setState({
selectedCBKeys: newSet
});
return;
}
this.setState(prevState => ({
...prevState,
selectedCBKeys: prevState.selectedCBKeys.add(key)
}));
console.log("new keys: ", key);
};
getKey = data => {
this.storeKey(data.key);
if (data.children) {
data.children.map(item => this.getKey(item));
}
};
render() {
const { selectedCBKeys } = this.state;
// rowSelection objects indicates the need for row selection
const rowSelection = {
selectedRowKeys: Array.from(selectedCBKeys),
onChange: (selectedRowKeys, selectedRows) => {
console.log(
`selectedRowKeys: ${selectedRowKeys}`,
"selectedRows: ",
selectedRows
);
},
onSelect: (record, selected, selectedRows) => {
this.getKey(record);
},
onSelectAll: (selected, selectedRows, changeRows) => {
console.log(
"onSelectAll: ",
selected,
" selectedRows: ",
selectedRows,
" changeRows: ",
changeRows
);
// selectedRows.map(item => this.getKey(item));
changeRows.map(item => this.getKey(item));
}
};
return (
<div className="parent">
<Table
columns={columns}
rowSelection={rowSelection}
dataSource={data}
/>
</div>
);
}
}
Here is the demo on stackblitz. Let me know,
From version 4.4.0, a much simpler one-liner solution is to set checkStrictly to false.
See more here for both demo and its specification, (Ctrl+F and search for the keyword "checkStrictly", both demo and its documentation are there)
rowSelection={{
checkStrictly: false,
onChange: (_, selectedRows) => {
setSelectedRows(selectedRows);
},
}}

Resources