How to pass data as parameter in react-table? - reactjs

How to pass data values as a parameter in React Table version 7.
I was trying to pass status and id in butFunction inside of react table so that i can create a function which create a button opposite of the status .
here is code what i had tried to do so.
Demo Link of the same code
const data = [
{ firstName: "Jane", lastName: "Doe", status: "OPEN" , id: "1" },
{ firstName: "John", lastName: "Smith", status: "CLOSE" , id: "2" },
{ firstName: "John", lastName: "Walker", status: "OPEN" , id: "3" }
];
const columns = [
{
Header: "First Name",
accessor: "firstName"
},
{
Header: "Last Name",
accessor: "lastName"
},
{
Header: "Status",
accessor: "status"
}
];
const Table = ({ columns, data }) => {
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow
} = useTable({
columns,
data
});
const butFunction = (level , id) => {
console.log(level)
console.log(id)
if (level === "OPEN") {
return <button > CLOSE </button>;
} else {
return <button > OPEN </button>;
}
};
return (
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>{column.render("Header")}</th>
))}
<th>Action</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>;
})}
<td>{butFunction(data.status, data.id)}</td>
</tr>
);
})}
</tbody>
</table>
);
};
export default function App() {
return (
<div className="App">
<Table columns={columns} data={data} />
</div>
);
}

You need to access row.values to access the data for each row. Inside the map function, row.values will be an object that contains the data for the current row.
Edit:
As per your comment, row.values object doesn't contains id property of your data objects. To access the id, use row.original.id
<td>{ butFunction(row.values.status, row.original.id) }</td>

Related

How to convert array to json and bind the json data in a table in react js

I have an array of,
I am trying to convert that to a JSON , so I can bind the data in a bootstrap table like this,
import "bootstrap/dist/css/bootstrap.min.css";
import Table from "react-bootstrap/Table";
function Home() {
const customers = [
{
CustomerId: 1,
Name: "John Hammond",
Country: "United States",
},
{
CustomerId: 2,
Name: "Mudassar Khan",
Country: "India",
},
{
CustomerId: 3,
Name: "Suzanne Mathews",
Country: "France",
},
{
CustomerId: 4,
Name: "Robert Schidner",
Country: "Russia",
},
];
return (
<div className="container">
<div className="row">
<div className="col-12">
<Table striped bordered hover size="sm">
<thead>
<tr>
<th>File Name</th>
<th>Username</th>
</tr>
</thead>
<tbody>
{customers.map(customers=>
<tr>
<td>{customers.Name}</td>
<td>{customers.Country}</td>
</tr>
)}
</tbody>
</Table>
</div>
</div>
</div>
);
}
export default Home;
Like in this example, they are binding Name and country from customers, I want to bind path data and mode data from the array and bind to the table.
I tried JSON.stringify but it is not working. How to do this?
This is the full code
import "bootstrap/dist/css/bootstrap.min.css";
import Table from "react-bootstrap/Table";
import { Octokit } from "octokit";
function Home() {
getContents();
let jsonString = '';
const customers = [
{
CustomerId: 1,
Name: "John Hammond",
Country: "United States",
},
{
CustomerId: 2,
Name: "Mudassar Khan",
Country: "India",
},
{
CustomerId: 3,
Name: "Suzanne Mathews",
Country: "France",
},
{
CustomerId: 4,
Name: "Robert Schidner",
Country: "Russia",
},
];
let contentResponse = "";
let valueArray = [];
async function getContents() {
try {
return await new Promise(async (resolve, reject) => {
try {
const octokit = new Octokit({
auth: "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",
});
const response = await octokit.request(
"GET /repos/KaranS0406/React/git/trees/4c1289a6405a5d87de6f1071ce723ee8b94be276?recursive=1"
);
console.log(response.data.tree);
contentResponse = response.data.tree;
Object.entries(contentResponse).forEach((element) => {
const [key, value] = element;
valueArray.push(value);
});
resolve("success");
} catch (error) {
reject("error");
}
});
} catch (error) {
console.log(error);
}
}
return (
<div className="container">
<div className="row">
<div className="col-12">
<Table striped bordered hover size="sm">
<thead>
<tr>
<th>File Name</th>
<th>Username</th>
</tr>
</thead>
<tbody>
{customers.map(customers=>
<tr>
<td>{customers.Name}</td>
<td>{customers.Country}</td>
</tr>
)}
</tbody>
</Table>
</div>
</div>
</div>
);
}
export default Home;
Add this after contentResponse line and check with console.log if is that what do you want.?
const convertdata = contentResponse.map((item) =>{
let obj={
Name:item.path,
Country:item.mode
}
})
Judging by what you get in the console, you already have what you need, just replace customers with your array (response.data.tree) and replace also name and country with path and mode.
{myArray.map(element =>
<tr>
<td>{element.path}</td>
<td>{element.mode}</td>
</tr>
)}

Minified react error on react-table when changing accessor conditionally

I have a data from an API and I want to display it in a table. So I decided to use react-table since its light-weight and is 'headless'. Now, I need to display multiple values with conditionals in one of the columns but I got this error instead:
Maximum update depth exceeded. This can happen when a component repeatedly calls setState
inside componentWillUpdate or componentDidUpdate. React limits the number of nested
updates to prevent infinite loops.
This is my code:
const columns = useMemo(() => [
{
Header: 'Id',
accessor: 'station_id'
},
{
Header: 'Type',
accessor: 'type_name'
},
{
Header: 'Location',
accessor: 'location',
Cell: (cell) => (
<span>
{cell.row.original.location},
{(cell.row.original.barangay === null ? '' : (cell.row.original.barangay === "") ? '' : cell.row.original.barangay + ', ')}
{(cell.row.original.municipality === null ? '' : (cell.row.original.municipality === "") ? '' : cell.row.original.municipality + ', ')}
{cell.row.original.province}
</span>
)
},
]);
const data = useMemo(() => stations, [])
const {
getTableProps,
getTableBodyProps,
headerGroups,
rows,
prepareRow,
} = useTable({ columns, data })
return (
<div>
<table {...getTableProps()}>
<thead>
{headerGroups.map(headerGroup => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map(column => (
<th {...column.getHeaderProps()}>{column.render('Header')}</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{rows.map((row) => {
prepareRow(row)
return (
<tr {...row.getRowProps()}>
{row.cells.map((cell) => {
return <td {...cell.getCellProps()}>{cell.render('Cell')}</td>
})}
</tr>
)
})}
<tr>
<td></td>
</tr>
</tbody>
</table>
</div>
)
And this is the sample of my data:
{
"station_id": "0016782",
"location": "l-1",
"barangay": "Brgy-1",
"municipality": "",
"province": "RXI",
"type_name": "P-Sensor",
},
Then I want the table to look like this:
Id | Type | Location
0016782 | P-Sensor | l-1, Brgy-1, RXI
In your code, columns is missing dependency.
It causes an error.
const columns = useMemo(() => [
{
Header: 'Id',
accessor: 'station_id'
},
{
Header: 'Type',
accessor: 'type_name'
},
{
Header: 'Location',
accessor: 'location',
Cell: (cell) => (
<span>
{cell.row.original.location},
{(cell.row.original.barangay === null ? '' : (cell.row.original.barangay === "") ? '' : cell.row.original.barangay + ', ')}
{(cell.row.original.municipality === null ? '' : (cell.row.original.municipality === "") ? '' : cell.row.original.municipality + ', ')}
{cell.row.original.province}
</span>
)
},
], []);

Getting Information/Data/Values from a row in React-Table

I literally have stayed up all night trying to figure out how to grab a value from my row.
const columns = useMemo(
() => [
{
// first group - TV Show
Header: "Shop Chop Chop List",
// First group columns
columns: [
{
Header: "User",
accessor: "email",
},
{
Header: "Store",
accessor: "store",
},
],
},
{
Header: "Details",
columns: [
{
Header: "Item",
accessor: "title",
},
{
Header: "Picture",
accessor: "picture",
Cell: ({ row }) => (
<a
target="_blank"
rel="noopener noreferrer"
href={row.original.picture}
>
{row.original.picture}
</a>
),
},
{
Header: "Aisle",
accessor: "aisleLocation",
},
{
Header: "Location",
id: 'edit',
accessor: 'id',
Cell: ({value}) => (
<div>
<button
onClick={()=> {
console.log(value);
}}
className={styles.editBtn}
>
Record Aisle
</button>
</div>
),
},
{
Header: "Remove",
id: "delete",
accessor: (str) => "delete",
Cell: (row)=> (
<button
className={styles.deleteBtn}
onClick={()=> {
const dataCopy = [...data];
dataCopy.splice(row.index, 1);
setData(dataCopy);
}}>
Found
</button>
)
}
],
},
],
[data],
);
This is my latest attempt. I am trying to grab a value from this row so I can assign a aisle location on the back end. I would prefer the uniqueID, but I could make it work with title and store as well. It is so damn hard to grab the information out of this row.
Here is my tableContainer
import React, { Fragment } from 'react';
import {
useTable,
useSortBy,
useFilters,
useExpanded,
usePagination,
} from 'react-table';
import { Table, Row, Col, Button, Input} from 'reactstrap';
import { Filter, DefaultColumnFilter } from './Filters';
const TableContainer = ({ columns, data, renderRowSubComponent }) => {
const {
getTableProps,
getTableBodyProps,
headerGroups,
page,
prepareRow,
visibleColumns,
canPreviousPage,
canNextPage,
pageOptions,
pageCount,
gotoPage,
nextPage,
previousPage,
state: { pageIndex },
} = useTable(
{
columns,
data,
defaultColumn: { Filter: DefaultColumnFilter },
initialState: { pageIndex: 0, pageSize: 5 },
},
useFilters,
useSortBy,
useExpanded,
usePagination
);
const generateSortingIndicator = (column) => {
return column.isSorted ? (column.isSortedDesc ? ' 🔽' : ' 🔼') : '';
};
const onChangeInInput = (event) => {
const page = event.target.value ? Number(event.target.value) - 1 : 0;
gotoPage(page);
};
return (
<Fragment>
<Table bordered hover {...getTableProps()}>
<thead>
{headerGroups.map((headerGroup) => (
<tr {...headerGroup.getHeaderGroupProps()}>
{headerGroup.headers.map((column) => (
<th {...column.getHeaderProps()}>
<div {...column.getSortByToggleProps()}>
{column.render('Header')}
{generateSortingIndicator(column)}
</div>
<Filter column={column} />
</th>
))}
</tr>
))}
</thead>
<tbody {...getTableBodyProps()}>
{page.map((row) => {
prepareRow(row);
return (
<Fragment key={row.getRowProps().key}>
<tr onClick={()=> handleShow(row.original)}>
{row.cells.map((cell) => {
return (
<td {...cell.getCellProps()}>{cell.render('Cell')}</td>
);
})}
</tr>
{row.isExpanded && (
<tr>
<td colSpan={visibleColumns.length}>
{renderRowSubComponent(row)}
</td>
</tr>
)}
</Fragment>
);
})}
</tbody>
</Table>
Please, can anyone help? I am new so very specific instructions are desired
please, and thank you
react-table is meant for displaying the data, not the JSX element but you can solve the issue in two ways, first, you can pass a unique id in the row data and just like above use that in the Cell or you can just render the JSX element as a row data and use the unique id directly(for example some model Id which you are trying to delete) but rendering the JSX element as a data is a heavy task as memoization will fail and you will have to do provide extra logic to prevent rerendering.

ReactJS - Adding value on specific table row

I created a react js app and have a table and it contains a button "Add Available Day" when I click it checkbox with days will show and when I choose a day it will automatically put in the table, however instead of updating specific row, changes are applied in all row. What I want to happen is for example I click add available day in first row then first row data must be updated not second and third row
This is my code:
import React from 'react';
import { Table, Button } from 'react-bootstrap';
const personData = [
{ id: 1, firstName: 'test1', lastName: 'test', day: [] },
{ id: 2, firstName: 'Jane', lastName: 'Doe', day: [] },
{ id: 3, firstName: 'John', lastName: 'Doe', day: [] },
{ id: 4, firstName: 'Clint', lastName: 'test', day: [] }
]
export default class App extends React.Component {
constructor() {
super();
this.state = {
day: [],
isSelectDay: false,
person: personData
}
}
handleSelectDay = (event) => {
let dayArr = [...this.state.day]
const value = event.target.value
const index = dayArr.findIndex(day => day === value);
if (index > -1) {
dayArr = [...dayArr.slice(0, index), ...dayArr.slice(index + 1)]
} else {
dayArr.push(value)
}
this.setState({ day: dayArr });
}
handleAddDay = () => {
this.setState({ isSelectDay: true })
}
render() {
const { isSelectDay, day } = this.state
const dayOptions = ["Monday, ", "Tuesday, ", "Wednesday", "Thursday, ", "Friday"].map((cur, ind) => {
return (
<div key={ind} className="checks" >
<label>
<input type="checkbox" name={cur} value={cur}
onChange={this.handleSelectDay} />{cur}
</label>
</div>
)
})
return (
<>
<Table striped bordered hover>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Days Available</th>
</tr>
</thead>
<tbody>
{this.state.person.length > 0 ? (
this.state.person.map((person) => (
<tr key={person.id}>
<td>{person.firstName}</td>
<td>{person.lastName}</td>
<td>{day}<Button variant="success" onClick={this.handleAddDay}>Add Available Day</Button></td>
</tr>
))
) : (
<tr>
<td colSpan={3}>No Data</td>
</tr>
)}
</tbody>
</Table>
<div style={{ display: isSelectDay ? 'block' : 'none' }}>
{dayOptions}
</div>
</>
)
}
}
Is this something you're after?
Demo
Full Code
I changed isSelectDay to personSelected so when you click 'Add Available Day' it'll switch to the correct person object from personData. I then used this to update the people object in the state (a copy of personData) to add/remove days from day array. The day array was then used to output the days.
import React from "react";
import { Table, Button } from "react-bootstrap";
var personData = [
{ id: 1, firstName: "test1", lastName: "test", day: [] },
{ id: 2, firstName: "Jane", lastName: "Doe", day: [] },
{ id: 3, firstName: "John", lastName: "Doe", day: [] },
{ id: 4, firstName: "Clint", lastName: "test", day: [] }
];
export default class App extends React.Component {
constructor() {
super();
this.state = {
personSelected: null,
people: personData
};
}
handleSelectDay = (event) => {
let dayArr = [...this.state.personSelected.day];
const value = event.target.value;
const index = dayArr.findIndex((day) => day === value);
if (index > -1) {
dayArr = [...dayArr.slice(0, index), ...dayArr.slice(index + 1)];
} else {
dayArr.push(value);
}
let newPeople = this.state.people;
newPeople.find((x) => x === this.state.personSelected).day = dayArr;
this.setState({ people: newPeople });
};
handleAddDay = (person) => {
this.setState({ personSelected: person });
document
.querySelectorAll("input[type=checkbox]")
.forEach((el) => (el.checked = false));
};
render() {
const { personSelected } = this.state;
const dayOptions = [
"Monday, ",
"Tuesday, ",
"Wednesday",
"Thursday, ",
"Friday"
].map((cur, ind) => {
return (
<div key={ind} className="checks">
<label>
<input
type="checkbox"
name={cur}
value={cur}
onChange={this.handleSelectDay}
/>
{cur}
</label>
</div>
);
});
return (
<>
<Table striped bordered hover>
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Days Available</th>
</tr>
</thead>
<tbody>
{this.state.people.length > 0 ? (
this.state.people.map((person) => (
<tr key={person.id}>
<td>{person.firstName}</td>
<td>{person.lastName}</td>
<td>
{person.day}
<Button
variant="success"
onClick={() => this.handleAddDay(person)}
>
Add Available Day
</Button>
</td>
</tr>
))
) : (
<tr>
<td colSpan={3}>No Data</td>
</tr>
)}
</tbody>
</Table>
{personSelected !== null && (
<div style={{ display: "block" }}>{dayOptions}</div>
)}
</>
);
}
}

I have a multidimensional object with several layers of nested arrays and I'm trying to map through all of them in one go but not sure how to

I have a complex object that I'm working with to build out a table of contact details, but I'm running into issues with the nested arrays.
I tried nested for loops and recently moved over to a nested .map() approach but I'm still hitting a wall where I can't access the final two arrays of objects (phone numbers and addresses) to print them out as well and I'm completely spinning my wheels.
I've been working on this for over a day and I'm completely stumped on how to approach this.
Expected Output:
Name | Member | Telephone | Email | Addresses
Ben B| Friend | 610-535-1234 | ben#gmail.com | 123 Fiction Drive,Denver
215-674-6789 234 Dreary Ln,Seattle
Alice | Family| 267-333-1234 | ally#aim.com | 437 Chance St, Pitts.
The Component:
const rows = contacts.contactGroups.map(group =>
<>
<thead>
<tr>
<td>Name</td>
<td>Member Type</td>
<td>Telephone</td>
<td>Email</td>
<td>Address</td>
</tr>
</thead>
<tbody>
<tr>{group.contactGroup}</tr>
<td>
<tr>
{group.contacts.map(contact => <td>
{contact.fullName}</td>)}
{group.contacts.map(contact => <td>
{contact.member}</td>)}
{/* {group.contacts.map(contact => <td>
</td>)}
{group.contacts.map(contact =>
<td>{contact.addresses}
</td>)} */}
</tr>
</td>
</tbody>
</>);
The data structure:
export default {
count: 1,
contactGroups: [
{
contactGroup: "Family",
count: 1,
contacts: [
{
member: "Uncle",
fullName: "BENJAMIN BILLIARDS",
lastName: "BILLIARDS",
firstName: "BENJAMIN",
email: "shark#billiards.com",
phoneNumbers: [
{
telephoneNumber: "123-456-7899",
type: "mobile"
},
{
telephoneNumber: "610-555-7625",
type: "work"
}
],
addresses: [
{
addressLine1: "123 FAMILY ST",
addressLine2: "APT 1208",
city: "ATLANTA",
state: "GEORGIA",
zipCode: "12345"
},
{
addressLine1: "456 WORKING BLVD",
addressLine2: "",
city: "ATLANTA",
state: "GEORGIA",
zipCode: "12345"
}
]
}
]
},
{
contactGroup: "Friends",
count: 1,
contacts: [
{
member: "School Friend",
fullName: "HANS ZIMMER",
lastName: "ZIMMER",
firstName: "HANS",
email: "hans#pirates.com",
phoneNumbers: [
{
telephoneNumber: "267-455-1234",
type: "mobile"
}
],
addresses: [
{
addressLine1: "789 FRIEND ST",
addressLine2: "",
city: "SAN DIEGO",
state: "CALIFORNIA",
zipCode: "67890"
},
{
addressLine1: "234 CANARY ST",
addressLine2: "",
city: "SEATTLE",
state: "WASHINGTON",
zipCode: "67890"
}
]
}
]
}
]
};
You can just simply use forEach which I think will be much easier to understand as follows:
https://codesandbox.io/s/clever-euclid-1bdl5
export const ContactsGrid = (props: Props) => {
const { contacts } = props;
const rows = [];
contacts.contactGroups.forEach(contactGroup => {
//First row for group name
const groupRow = (
<tr>
<td>{contactGroup.contactGroup}</td>
</tr>
);
// Data for that group
const contactRows = [];
contactGroup.contacts.forEach(contact => {
const row = (
<tr>
<td>{contact.fullName}</td>
<td>{contact.member}</td>
<td>
{contact.phoneNumbers.map(number => (
<div>
{number.type} : {number.telephoneNumber}
</div>
))}
</td>
<td>{contact.email}</td>
<td>
{contact.addresses.map(add => (
<div>
{add.addressLine1}
<br /> {add.addressLine2} <br /> {add.city}, {add.state}
<br />
{add.zipCode}
</div>
))}
</td>
</tr>
);
contactRows.push(row);
});
// Add the group row and all the data rows to final rows arr to be rendered
rows.push(groupRow, ...contactRows);
});
return (
<table>
<thead>
<tr>
<td>Name</td>
<td>Member Type</td>
<td>Telephone</td>
<td>Email</td>
<td>Address</td>
</tr>
</thead>
<tbody>{rows}</tbody>
</table>
);
};
Hope this helps !
Another approach, according to your expected output table
https://codesandbox.io/s/suspicious-leaf-ozwu1?fontsize=14&hidenavigation=1&theme=dark
interface Row {
name: string;
memberOf: string;
memberType: string;
telephones: Array<PhoneNumber>;
email: string;
addresses: Array<Address>;
}
export const ContactsGrid = (props: Props) => {
const { contacts } = props;
let rows: Array<Row> = [];
contacts.contactGroups.forEach(contactG => {
contactG.contacts.forEach(contact => {
rows.push({
name: contact.fullName,
memberOf: contactG.contactGroup,
memberType: contact.member,
telephones: contact.phoneNumbers,
email: contact.email,
addresses: contact.addresses
});
});
});
return (
<table>
<thead>
<tr>
<td>Name</td>
<td>Member Type</td>
<td>Telephone</td>
<td>Email</td>
<td>Address</td>
</tr>
</thead>
<tbody>
{rows.map(row => {
return (
<tr>
<td>{row.name}</td>
<td>{row.memberType + " (" + row.memberOf + ")"}</td>
<td>
{row.telephones.map(phone => {
return <p>{phone.telephoneNumber}</p>;
})}
</td>
<td>{row.email}</td>
<td>
{row.addresses.map(address => {
return <p>{address.addressLine1 + ", " + address.city}</p>;
})}
</td>
</tr>
);
})}
</tbody>
</table>
);
};

Resources