How can I do Up and down key navigation in table row? - reactjs

Only want to navigate the mos id row with the help of up and down key but right now only all row mos id, duration navigate with this code.
please help
Code:
` const MouseKeyDown = async (event, id) => {
const actives = document.activeElement;
switch (event.key) {
case "ArrowUp":
return actives?.previousElementSibling?.focus();
case "ArrowDown":
// event.target && event.target.focus();
event.preventDefault();//Scroll With row , not table
return actives?.nextElementSibling?.focus();
default:
break;
}
}
<tbody>
{
dataName.map((value, index) => {
return (
<tr key={index} className="border_bottom"
>
<td onClick={() => CopyClipborad(value.Name)} className="FocusRow"
tabIndex={index} onKeyDown={(e) => { MouseKeyDown(e); }}>{value.Name}</td>
<td>{value.Name}</td>
<td>{value.Name}</td>
</tr>
)
})
}
</tbody>
`

Related

Why the onChange event returning the previous value of dropdown?

I am trying to make a demo invoice with react and firebase. The goal is to autofill the item code and item price after getting the "itemname" value from dropdown. But at the initial change, its still showing the default values of the states. And from the 2nd change of dropdown, its collecting the previous "itemname" and filling "itemprice" and "itemcode" accordingly while in dropdown the itemname is changed.
const [items, setItems]: any = useState([]);
const [itemName, setItemName]:any = useState ("banana");
const [itemUnitPrice, setItemUnitPrice] = useState(10);
const [itemCode, setItemCode] = useState(20349);
const handleItemNameChange = (e:any) => {
e.preventDefault();
console.log("this is e", e);
{ setItemName(e.target.value)}
{items.length != 0 && itemName != undefined && autofillItemDetails(items, itemName)}
}
function autofillItemDetails(itms:any, itmName:string) {
console.log("autofill fuction ran");
let i
for(i = 0; i<items.length; i++){
if (items[i].fruitname === itemName) {
setItemUnitPrice(items[i].price)
setItemCode(items[i].code)
console.log("this is i", i);
console.log("this is fruitname", items[i].fruitname);
console.log("this is price", items[i].price);
// break
}
}
}
useEffect(() => {
getDocs(colRef)
.then((snapshot) => {
let itemsFirebase:any = []
snapshot.docs.forEach((doc) => {
itemsFirebase.push({...doc.data(), id:doc.id});
// console.log("this is itemsfirebase",itemsFirebase)
setItems(itemsFirebase)
})
})
}, [])
console.log("this is items",items
console.log("this is itemname", itemName)
return (
<table width='100%'>
<thead>
<tr>
<td>Item Code</td>
<td>Item Name</td>
<td>Unit Price</td>
<td>Qty</td>
<td>Total</td>
</tr>
</thead>
<tbody>
<tr className="h-10">
<td>{itemCode}</td>
<td>
<select onChange={handleItemNameChange} value={itemName}>
{items.map((item:any) => (
<option key = {item.id}> {item.fruitname} </option>
))}
{/* <option>Grapefruit</option>
<option>Mango</option>
<option>coconut</option>
<option>Litchi</option>
<option>Banana</option> */}
</select>
</td>
<td>{itemUnitPrice}</td>
<td>129</td>
<td>1032</td>
</tr>
</tbody>
</table>
)
}

use useMemo for large tables in react without react-table

I have a table that has a big database, 2k lines +
So I had a function to filter and organize this working, but it takes 1-2 secs to filter, is it possible to do with useMemo or useCallBack since I always need to redo the database?
export default function Table(props) {
const [order, setOrder] = useState(true);
function handleHeaderClick(clickedHeader) {
setOrder(!order);
const newdata = props.data.sort((a, b) => {
const x = a[clickedHeader];
const y = b[clickedHeader];
if (order && x > y) return -1;
return 1;
});
props.setdata(newdata);
}
function createHeader(header, index) {
if (header.includes("BET") || header.includes("C") || header.includes("CHECK")) {
return (
<th onClick={(e) => handleHeaderClick(header)} key={index}>
{header}
</th>
);
}
}
function createRow(row) {
// ♠♥♦♣
try {
return row.replace(/s/g, "♠").replace(/d/g, "♦").replace(/c/g, "♣");
} catch (e) {
return row;
}
}
function tableRow(row, indexRow) {
return (
<tr key={indexRow}>
{Object.keys(row).map((hd) => {
const value = createRow(props.data[indexRow][hd]);
if (hd.includes("BET") || hd.includes("C") || hd.includes("CHECK")) {
return (
<td className={value[1]} key={hd}>
{value}
</td>
);
}
})}
</tr>
);
}
return (
<table>
<thead>
<tr>{Object.keys(props.data[0]).map((header, indexHeader) => createHeader(header, indexHeader))}</tr>
</thead>
<tbody>{props.data.map((row, indexRow) => tableRow(row, indexRow))}</tbody>
</table>
);
}
I think I have to change something in my handleHeaderClick function, I have already tried some solutions of this type
const test = useMemo(() => handleHeaderClick, [props.data]);
but my code stops working
where's my table
#edit violation on chrome
[Violation] 'setTimeout' handler took 1458ms
#edit2
On firefox works correct

React-table hide various columns from button click

I have a react-table with a primary header containing multiple secondary headers underneath it. When the primary header is clicked I want all but one secondary header with name 'deposit' to be hidden, or shown (toggle). See screenshot.
I have a solution using column.toggleHeader(column.isVisible). I both wanted to demonstrate this as there wasn't a lot of material out there for how to do this; and I'm wondering if there are neater solutions using .getToggleHiddenProps. To be honest I don't understand what is going on with IndeterminateCheckbox eg. https://github.com/TanStack/table/discussions/1989 and how that would be used with specific column header values.
My answer below.
Just some background - this is a Web3 app that is getting information about Crypto wallets - hence why the code looks for '0x' and reduces the column header value to const headerShortened = header.substr(0,5) + '...' + header.substr(header.length - 4,header.length) (So 0x123abcFED1239876 becomes ox123...9876)
I've just finished this initial version so don't AT me for any rough edges. Though happy to receive constructive feedback.
interface DataTableProps {
data: any
columns: Column<DripRowFormat>[]
}
interface AHeaderProps {
column: ColumnInstance<DripRowFormat>
allColumns: Array<ColumnInstance<DripRowFormat>>
}
export function DataTable({data, columns}: DataTableProps) {
const [hiddenColumns, setHiddenColumns] = useState<string[]>([])
const initialState = {hiddenColumns}
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
allColumns,
getToggleHideAllColumnsProps,
state
} = useTable({columns, data, initialState});
// console.log(`table input: ${JSON.stringify(data, null, 2)}`)
// console.log(`table rows: ${Util.inspect(rows)}`)
// console.log(`getTableProps: ${JSON.stringify(getTableProps())}`)
// console.log(`allColumns: ${Util.inspect(allColumns)}`)
const RenderHeader = ({column, allColumns}: AHeaderProps) => {
const colHeaderClick = (e: React.MouseEvent<HTMLButtonElement>) => {
e.preventDefault()
// Now call column.toggleHidden() for all cols but 'deposit' - so when Hidden only Deposit is shown
const childColumnsNotDeposit = allColumns.filter(c =>
column.Header && c.Header && c.parent
&& c.Header.toString().toLowerCase() !== 'deposit'
&& c?.parent?.Header?.toString() === column.Header)
childColumnsNotDeposit.forEach(c => {
c.toggleHidden(c.isVisible)
})
}
const drawHeaderWRTVisibleColumns = (column: ColumnInstance<DripRowFormat>): ReactNode => {
if (! column) {
return (
<span>NOT COL</span>
)
}
const childCols = column.columns?.filter(c => c.isVisible)
// #ts-ignore
if (childCols && childCols.length < column?.columns?.length) {
// #ts-ignore
const header = column.Header.toString()
const headerShortened = header.substr(0,5) +
'...' + header.substr(header.length - 4,header.length)
return (
<span>{headerShortened}</span>
)
} else {
return column.render('Header')
}
}
// #ts-ignore
if (column.placeholderOf?.Header.startsWith('0x')) {
return (
<button onClick={colHeaderClick}>{drawHeaderWRTVisibleColumns(column)}</button>
)
} else if (column.Header?.toString().startsWith('0x')) {
return (
<button onClick={colHeaderClick}>{drawHeaderWRTVisibleColumns(column)}</button>
)
} else {
return (
<span>{column.render('Header')}</span>
)
}
}
return (
<div>
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
// #ts-ignore
<th {...column.getHeaderProps()}><RenderHeader column={column} allColumns={allColumns}/></th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row, i) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map(cell => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
</tbody>
</table>
</div>
);
}

Removing Item from DOM display (React)

sample image of page so far
Please see the above image. I'm wanting to be able to remove the string in the "skill" column when it is deleted after clicking the "Delete" button on the right. I can delete an Employee using filter() with the Delete button on the left. This removes the entire row from the DOM, which is great, but I would like the Delete button on the right to simply remove the content from the Skill(s) column for that particular employee.
I have tried doing something similar in the deleteSkill() function, but I am not sure how to remove the content of the Skill(s) column without deleting the entire row. The issue lies in my setList() function within my deleteSkill() function. Any ideas would be greatly appreciated.
Here is the code:
import React, { Fragment, useEffect, useState } from 'react';
const List = () => {
const [list, setList] = useState([]);
//DELETE Employee by ID
const deleteEmployee = async (id) => {
try {
const deleteEmployee = await fetch(`http://localhost:5000/employees/${id}`, {
method: "DELETE"
});
setList(list.filter(item => item.employee_uuid !== id));
} catch (err) {
console.error(err.message)
}
};
//DELETE Skill by ID
const deleteSkill = async (id) => {
try {
const deleteSkill = await fetch(`http://localhost:5000/employees/${id}/skills`, {
method: "DELETE"
});
setList(list.filter(item => item.summary !== id));
} catch (err) {
console.error(err.message)
}
};
const getList = async () => {
try {
const response = await fetch("http://localhost:5000/employees")
const jsonData = await response.json();
setList(jsonData);
} catch (err) {
console.error(err.message);
}
};
useEffect(() => {
getList();
}, []);
console.log(list);
return (
<Fragment>
{" "}
<h1 class="text-center">Employee Skills Tracker</h1>
<table class="table mt-5 text-center">
<thead>
<tr>
<th>Firstname</th>
<th>Lastname</th>
<th></th>
<th></th>
<th>Skill(s)</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{list.map(item => (
<tr key={item.employee_uuid}>
<td>{item.firstname}</td>
<td>{item.lastname}</td>
<td>Edit</td>
<td><button className="btn btn-danger" onClick={() => deleteEmployee(item.employee_uuid)}>Delete</button></td>
<td>{item.summary}</td>
<td>Edit</td>
<td><button className="btn btn-danger" onClick={() => deleteSkill(item.employee_uuid)} >Delete</button></td>
</tr>
))}
</tbody>
</table>
</Fragment>
);
};
export default List;
Instead of using list.filter(), use list.map(). The key is that you want to return a 1:1 list of modified elements, not a list without certain elements.
If you want to remove the summary for just a specific employee, I'd recommend
setList(list.map(item => {
if (item.id !== id) {
return item; // not the right employee, pass it through
}
let newItem = {...item};
delete newItem.summary;
return newItem;
}));
It's more complex, because you have to explicitly return what you want, but it's also what you're asking for.

Sorting Columns reactjs table

I'm trying to write a reactjs table for an assignment and am having trouble getting a sorting component working on the columns of my table. Most of this was duplicated from a previous post and I tried to integrate my data into the mold, but I am getting no results. Any idea why the code I have might not be working? Thanks!
class UserTable extends React.Component {
constructor(props){
super(props)
this.state = {
users: this.props.users,
sort: {
column: null,
direction: 'desc',
}
}
}
onSort = (column) => {
return e => {
const direction = this.state.sort.column ? (this.state.sort.direction === 'asc' ? 'desc' : 'asc') : 'desc'
const sortedUsers = this.state.users.sort((a, b) => {
if (column === 'name.first') {
const nameA = a.name.first.toUpperCase() // ignore upper and lowercase
const nameB = b.name.first.toUpperCase() // ignore upper and lowercase
if (nameA < nameB)
return -1
if (nameA > nameB)
return 1
else return 0
}
else {
return a.name.first - b.name.first
}
})
if (direction === 'desc') {
sortedUsers.reverse()
}
this.setState({
users: sortedUsers,
sort: {
column,
direction,
},
})
}
}
const setArrow = (column) => {
let className = 'sort-direction';
if (this.state.sort.column === column) {
className += this.state.sort.direction === 'asc' ? ' asc' : ' desc';
}
return className;
};
render() {
return (
<table>
<thead>
<tr>
<th onClick={this.onSort('name.first')}>
First Name
<span className={this.setArrow('name.first')}></span>
</th>
<th onClick={this.onSort('name.last')}>
Last Name
<span className={this.setArrow('name.last')}></span>
</th>
<th onClick={this.onSort('company')}>
Company
<span className={this.setArrow('company')}></span>
</th>
<th onClick={this.onSort('phone')}>
Phone
<span className={this.setArrow('phone')}></span>
</th>
<th onClick={this.onSort('email')}>
Email
<span className={this.setArrow('email')}></span>
</th>
<th onClick={this.onSort('birthdate')}>
Birthdate
<span className={this.setArrow('birthdate')}></span>
</th>
</tr>
</thead>
<tbody>
{this.state.users.map((user, index) => {
return (
<tr>
<td>{user.name.first}</td>
<td>{user.name.last}</td>
<td>{user.company}</td>
<td>{user.phone}</td>
<td>{user.email}</td>
<td>{user.birthdate}</td>
</tr>
);
})}
</tbody>
</table>
);
}
}
ReactDOM.render(<UserTable users={users} />, document.getElementById('container'));
You should return a function in onSort handler since event handlers take reference of a function but in your case they are getting undefined because you are invoking function and nothing returned.
So you code should looks like this:
onSort = column => {
return e => {
const direction = this.state.sort.column ? (this.state.sort.direction === 'asc' ? 'desc' : 'asc') : 'desc'
const sortedUsers = this.state.users.sort((a, b) => {
if (column === 'name.first') {
const nameA = a.name.first.toUpperCase() // ignore upper and lowercase
const nameB = b.name.first.toUpperCase() // ignore upper and lowercase
if (nameA < nameB)
return -1
if (nameA < nameB)
return 1
else return 0
}
else {
return a.name.first - b.name.first
}
})
if (direction === 'desc') {
sortedUsers.reverse()
}
this.setState({
users: sortedUsers,
sort: {
column,
direction,
},
})
}
}

Resources