I have a array of employee objects and i'm using that array(passed as state) to build rows in a table(as shown below). I get this error while iterating over the array. when I display the array using {props.employee_data}(the line is commented)
TypeError: Cannot read property 'map' of null
Code:
export default function(props) {
let employees = null
return (
<Table striped bordered hover size="sm">
<thead>
<tr>
<th>Full Name</th>
<th>Gender</th>
<th>Current Annual Salary</th>
<th>2018 Gross Pay Received</th>
<th>2018 Overtime Pay</th>
<th>Department</th>
<th>Department Name</th>
<th>Division</th>
<th>Assignment Category</th>
<th>Employee Position Title</th>
<th>Position Under-filled</th>
<th>Date First Hired</th>
</tr>
</thead>
<tbody>
{/* <tr>
<td>1</td>
<td>Mark</td>
<td>Otto</td>
<td>#mdo</td>
</tr>
*/}
{/* {props.employee_data} */}
{props.employee_data.map((employee)=>{
return <tr>employee</tr>
}
)}
</tbody>
</Table>
)
}
parent component
class App extends Component {
constructor(props){
super(props)
this.state = {
employee_data: null,
column_names: null
}
}
componentDidMount = () => {
this.fetchData();
}
fetchData = async () => {
fetch(county_data).
then(response => response.json()).
then(response => {
console.log(response.data)
let column_names = response.meta.view.columns.map((item)=>{
return item['name']
})
// console.log(JSON.stringify(response.data))
this.setState({
employee_data: response.data,
column_names: column_names
})
})
}
render() {
return (
<div className="App">
<Container>
<Row>
<Col lg={4}>1 of 3</Col>
<Col lg={4}>2 of 3</Col>
<Col lg={4}>2 of 3</Col>
</Row>
</Container>
<br></br>
<br></br>
<DataTable employee_data={this.state.employee_data}/>
</div>
);
}
}
export default App;
Initially the employee_data is null, it is not until your fetch, the employee data is an array.
map is a function on the array's prototype, hence it will not be available on the initial employee_data which is null. Only after the fetch, the employee data is an array and the map function is available.
To get around this, you can initially declare employee_data as an empty array.
this.state = {
employee_data: [],
... other state data,
}
you can do th
export default function(props) {
let employees = props.employee_data?props.employee_data:[];
return (
<Table striped bordered hover size="sm">
<thead>
<tr>
<th>Full Name</th>
<th>Gender</th>
<th>Current Annual Salary</th>
<th>2018 Gross Pay Received</th>
<th>2018 Overtime Pay</th>
<th>Department</th>
<th>Department Name</th>
<th>Division</th>
<th>Assignment Category</th>
<th>Employee Position Title</th>
<th>Position Under-filled</th>
<th>Date First Hired</th>
</tr>
</thead>
<tbody>
{/* <tr>
<td>1</td>
<td>Mark</td>
<td>Otto</td>
<td>#mdo</td>
</tr>
*/}
{/* {props.employee_data} */}
{employees.map((employee)=>{
return <tr>employee</tr>
}
)}
</tbody>
</Table>
)
}
Related
I have passed an array of objects in useState hook as the initial state and i want to iterate over it using map method in other component, i have passed the current state as prop in the other object and have used map method over it but console message still shows values.map is not a function, i know we can only use map method on array i have done that only still the error shows.
created state and passed an array of objects-
const [values, setValues] = useState([
{
name: "Vansh",
age: 22,
email: "vansh#gmail.com",
},
]);
Passed values as props in Home component-
<Home
addFormData={addFormData}
setAddFormData={setAddFormData}
values={values}
setValues={setValues}
/>
Code of my home component-
const Home = ({ values }) => { return (
<div>
<table>
<thead>
<tr>
<th>name</th>
<th>age</th>
<th>email</th>
</tr>
</thead>
<tbody>
{values.map((val, index) => (
<tr>
<td key={val.index}>{val.name}</td>
<td key={val.index}>{val.age}</td>
<td key={val.index}>{val.email}</td>
</tr>
))}
</tbody>
</table>
<Link to="/form">
<button>FORM</button>
</Link>
</div> ); };
Please see the code it's working fine export below your missing export.
const Home = ({ values }) => {
// console.log(values);
return (
<div>
<table>
<thead>
<tr>
<th>name</th>
<th>age</th>
<th>email</th>
</tr>
</thead>
<tbody>
{values.map((val, index) => (
<tr>
<td key={val.index}>{val.name}</td>
<td key={val.index}>{val.age}</td>
<td key={val.index}>{val.email}</td>
</tr>
))}
</tbody>
</table>
</div>
);
};
export default Home;
Please see the code SandBoxLink
I need to pass params from child component to the node elements from parent props.
Page component
export default function Categories() { const dispatch = useDispatch();
useEffect(() => {
dispatch(loaderAction(false));
return () => dispatch(loaderAction(true)); }, [dispatch]);
function handleClick(params) {
alert(); }
function handleEditClick(params) {
alert(); }
return (
<div className="categories-body">
<div className="categories-header">
<div className="left">
<h2>{t('[categories]')}</h2>
</div>
<div className="right">
<button className="button orange">{t('[addNewCategory]')}</button>
<LanguageSettings name="categoriesLanguageSetting" />
</div>
</div>
// Table component imported
<Table
action={
<>
//node elements
<button onClick={handleClick}>save</button>
<button onClick={handleEditClick}>edit</button>
</>
}
/>
</div> ); }
TableComponent
export default function Table({action}) {
return (
<table>
<thead>
<tr>
<th>Name</th>
<th>date</th>
<th>key</th>
<th>category</th>
<th>actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>{action}</td> //pass parameter to node props
</tr>
</tbody>
</table>
);
}
I have pass two buttons to the Table component and need to pass for example row id to button onClick
Just pass the function... not the component
const handleClick = id => alert();
<Table action={handleClick} />
function Table({action}) {
return (
<table>
...
<td><button onClick={() => action(`someId`)}>action</button></td>
</table>
);
}
Or if you insist, pass a function component not an element:
actions={({id}) => <button onClick={() => handleClick(id)}>save</button>}
// Usage
function Table({action}) {
const Action = props.action;
return (
<table>
...
<td><Action id="Some id"/></td>
</table>
);
}
in your page component, just pass the actions prop as a render prop function
function handleClick(params) {
console.log(params);
alert();
}
function handleEditClick(params) {
console.log(params);
alert();
}
return (
<Table
action={ (params) => (
<>
<button onClick={() => handleClick(params)}>save</button>
<button onClick={() => handleEditClick(params)}>edit</button>
</>
)
}
/>
)
and in the table component call that function with the desired params,
with this approach, you can extend the render prop function to deliver multiple params
function Table({action}) {
return (
<table>
<thead>
<tr>
<th>Name</th>
<th>date</th>
<th>key</th>
<th>category</th>
<th>actions</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>1</td>
<td>1</td>
<td>1</td>
<td>{action(23)}</td> // pass params here
</tr>
</tbody>
</table>
);
}
I have a question about the component panel in react
Currently, I have a requirement to create a common component for the Order and Product tables. But the two tables have different numbers of columns, one side has many columns and one side has few columns, besides there are also different table names.
I have a piece of code like this
import React from 'react';
import {Table, Image} from 'react-bootstrap';
import '../Table/index.css';
import Button from '../Button/index';
const TableItem = ({productList}) => {
return(
<Table striped bordered hover>
<thead>
<tr>
<th>No. </th>
<th>Image</th>
<th>Name</th>
<th>Category</th>
<th>Price</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{productList.map((product, index) => (
<tr key={index}>
<td>{product.id}</td>
<td><Image src={product.image} /></td>
<td>{product.name}</td>
<td>{product.category}</td>
<td>{product.price}</td>
<td>
<Button variant="success" onClick={redirectToEdit}>Edit</Button>
<Button variant="danger" onClick={deleteProductItem}>Delete</Button>
</td>
</tr>
))}
</tbody>
</Table>
);
}
export default TableItem;
That code I have created for the product table, but the order table is not because I do not know how to do it properly. I named fixed for the column, I know this is wrong because the order table will also retrieve components from this table, so I can not make the name like that
The order table also has the following columns: Username, address, quantity, status .....
How can I change the code in this component that can be used for both tables
Can anyone help me to explain for this, thank you so much
So you can do something like this, create a table component and pass the columns list and data in there as props that way you can control the table from the parents component and can be used in any way as you want.
const TableItem = ({data, columns}) => {
return(
<Table striped bordered hover>
<thead>
<tr>
{
columns.map((column, index) => {
<th key={ index }>{ column.name }</th>
}
}
</tr>
</thead>
<tbody>
{data.map((product, index) => (
<tr key={index}>
<td>{product.id}</td>
<td><Image src={product.image} /></td>
<td>{product.name}</td>
<td>{product.category}</td>
<td>{product.price}</td>
<td>
<Button variant="success" onClick={redirectToEdit}>Edit</Button>
<Button variant="danger" onClick={deleteProductItem}>Delete</Button>
</td>
</tr>
))}
</tbody>
</Table>
);
}
and in the parent component you can do something like
const parentComponent = () => {
return {
<TableItem columns={ productColumns } data={ productData } />
<TableItem columns={ orderColumns } data={ orderData }
}
}
Note Code not tested and is pseudo
You can pass columns (Array) as a props and render it.
const columns = ['username', 'quantity', 'etc'];
const TableItem = ({List, columns}) => {
return(
<Table striped bordered hover>
<thead>
<tr>
{columns.map((name, index) => (
<th key={index}>{name}</th>
))}
</tr>
</thead>
<tbody>
</Table>
)
})
If you have some common columns then you can pass one more props commonColumns like that.
const TableItem = ({List, columns, commonColumns}) => {
return(
<Table striped bordered hover>
<thead>
<tr>
{commonColumns.map((name, index) => (
<th key={index}>{name}</th>
))}
{columns.map((name, index) => (
<th key={index}>{name}</th>
))}
</tr>
</thead>
<tbody>
</Table>
)
})
Hope this will help you.
i have a very annoying error when trying to display stuff in react table , i would like to make a table and display all values in rows , but for some reason i am getting this error saying Adjacent jsx elemetns must be wrapped in an enclosing element next to the line where im trying to map over results. Any help is greatly appreciated !! thanks!!!
import React from "react";
import "./index.css";
// could also import the sass if you have a loader at dayz/dayz.scss
import moment from 'moment';
import { tasksRef, timeRef } from './firebase';
const defaultColor = "#000";
class Show extends React.Component {
state = {
Events: [],
loading: true
};
render(){
const { Events, Loading } = this.state;
const orderedcars = Events;
let List;
if (Loading) {
List = <div className="TaskList-empty">Loading...</div>;
} else {
List = (
<div>
<table>
<thead>
<tr>
<th scope="row">Event Name</th>
<th scope="row">Event date</th>
<th scope="row">Event timeRef</th>
</tr>
</thead>
<tbody>
{Events.map(car => (
<tr>
<td>{car.name}</td>
<td>{car.timeRef}</td>
<td>{car.description}</td>
</tr>
</tbody>
</table>
))}
</div>
);
}
return(
<div>
{List}
</div>
);
}
}
export default Show;
the problem is that the closing tbody and table atgs should be outside map function as follows
{Events.map(car => (
<tr key={car.name}>
<td>{car.name}</td>
<td>{car.timeRef}</td>
<td>{car.description}</td>
</tr>
))}
You want to place the closing </tbody> and </table> tags outside of the function given to Events.map.
List = (
<div>
<table>
<thead>
<tr>
<th scope="row">Event Name</th>
<th scope="row">Event date</th>
<th scope="row">Event timeRef</th>
</tr>
</thead>
<tbody>
{Events.map(car => (
<tr>
<td>{car.name}</td>
<td>{car.timeRef}</td>
<td>{car.description}</td>
</tr>
))}
</tbody>
</table>
</div>
);
I have a table of rows that display contact information. I'd like to have it render a messasge of "No contacts" when the listItems array is 0. I tried creating a const noEntries variable and setting it with the array to 0, and using {noEntries No entries}, but this is throwing an error.
class ContactList extends Component {
constructor(props) {
super(props);
this.createContact = this.createContact.bind(this);
}
delete(key) {
this.props.delete(key);
}
createContact(item) {
return <tr key={item.key}>
<td>{item.firstname}</td>
<td>{item.lastname}</td>
<td>{item.phone}</td>
<td><i className="fas fa-trash-alt" onClick={() => { if (window.confirm('Are you sure you want to delete ' + item.firstname + ' ' + item.lastname + ' from your contacts?')) this.delete(item.key)}}></i></td>
</tr>
}
render() {
const contactEntries = this.props.entries;
const listItems = contactEntries.map(this.createContact);
return (
<table className="mui-table mui-table--bordered">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
{listItems}
</tbody>
</table>
);
}
};
export default ContactList;
in your render() do like this:
render() {
const contactEntries = this.props.entries;
const listItems = contactEntries.map(this.createContact);
return (
contactEntries.length > 0?
<table className="mui-table mui-table--bordered">
<thead>
<tr>
<th>First Name</th>
<th>Last Name</th>
<th>Phone</th>
</tr>
</thead>
<tbody>
{listItems}
</tbody>
</table>:<span>No results</span>
);
}
check the number of records in contactEntries using ternary operator if length ==0 then return no data component else return rows
const listItems = contactEntries && contactEntries.length >0
? contactEntries.map(this.createContact)
: <tr key={item.key}>
<td rowspan="3">No data</td
</tr>