Getting error "props.data.map is not a function" in React - javascript

I am trying to make a form where on submit the data will be displayed in the table below. I have created Form and Table components and passing the form data into Table component. In the table component I have created 2 components; TableHeader and TableBody and passing the data to TableBody from Table. However, I am getting an error:
props.data.map is not a function
Here is my code:
Form.js
import React, { Component } from 'react';
import DisplayTable from '../Components/Table';
import Jumbotron from 'react-bootstrap/Jumbotron';
import Container from 'react-bootstrap/Container';
class Form extends Component {
constructor(){
super();
//1st 3 state fields will fetch the input data and next 3 will store the updated state into it
this.state={
first:'',
last:'',
email:'',
firstU:'',
lastU:'',
emailU:''
};
this.onInputChange=this.onInputChange.bind(this);
this.onInputSubmit=this.onInputSubmit.bind(this);
}
//on input change captures the values of the fields into respective input fields (first,last,email)
onInputChange=(event)=>{
this.setState({
[event.target.name]:event.target.value
}
)
//console.log(event.target.value);
// console.log('input change running');
}
//sets the values on submit
onInputSubmit=()=>{
// this.setState();
//console.log(this.state.first);
this.submitData(this.state.first,this.state.last,this.state.email);
//console.log('input submit running');
}
//sets the onChange state into new state fields
submitData=(first,last,email)=>{
this.setState({
firstU:first,
lastU:last,
emailU:email
});
console.log('submitData running');
}
render() {
return (
<Jumbotron fluid>
<Container>
<h1>Form</h1>
<div className="App" align="center">
<div class="row">
<input
name="first"
onChange={this.onInputChange}
type="text"
value={this.state.first}
/>
</div>
<div class="row">
<input
name="last"
onChange={this.onInputChange}
type="text"
value={this.state.last}
/>
</div>
<div class="row">
<input
name="email"
onChange={this.onInputChange}
type="email"
value={this.state.email}
/>
</div>
<div class="row">
<button name="submit" onClick={this.onInputSubmit}>
Submit
</button>
</div>
</div>
{/*here passed entire state into single variable instead of passing like
this.state.first,this.state.last to reduce code
*/}
<DisplayTable data={this.state}/>
</Container>
</Jumbotron>
);
}
}
export default Form;
Table.js
import React, { Component } from 'react';
import Jumbotron from 'react-bootstrap/Jumbotron';
import Container from 'react-bootstrap/Container';
import Table from 'react-bootstrap/Table';
//props.data will fetch value from the state
class DisplayTable extends Component{
render(){
//console.log("hi"+this.props.data.first);
//const data=this.props;
return (
<Jumbotron fluid>
<Container>
<h1>Data</h1>
<TableHeader/>
<TableBody data={this.props}/>
</Container>
</Jumbotron>
);
}
}
const TableHeader= ()=> {
return(
<div>
<Table striped bordered hover variant="dark">
<thead>
<tr>
<th>#</th>
<th>First Name</th>
<th>Last Name</th>
<th>email</th>
</tr>
</thead>
</Table>
</div>
);
}
const TableBody = (props)=> {
console.log("k"+props.data.first)
const rows=props.data.map((row,index)=>{
return(
<div>
<Table striped bordered hover variant="dark">
<tbody>
<tr>
<td key={index}></td>
<td>{row.first}</td>
<td>{row.last}</td>
<td>{row.email}</td>
</tr>
</tbody>
</Table>
</div>
);
})
return ({rows});
}
export default DisplayTable;

A good way to go about solving this problem might be to edit your state like so:
this.state = {
users: [
{
first: 'name',
last: 'name',
etc...
},
{
first: 'name',
last: 'name',
etc...
}
],
other: state //if need be
}
This way, you have an array of users and can add more users to the table as needed.
Then you just pass this.state.users to your child component through props.

Is your props.data is an array because map works with array only. I think your data is in {} but not in []. Please verify.
print the data to verify it.

Related

Display the selected item to another component using react hooks

I have a section in which contains templates, now I want a user to select one of the templates and edit the data in templates eg name, job title, contact etc.
Here is my live demo in code sandbox editor live demo
Here is templates.js
export default function Templates() {
const [selected, setSelected] = useState("");
let history = useHistory();
const handleSelected = (e) => {
const value = e.target.innerHTML;
setSelected(value);
history.push('/Settings')
};
return (
<div className="App">
<h2>Select one of the Template below by clicking title</h2>
<div className={`template_one ${selected === "Template_one" ? "selected" : "unselected"}`} onClick={(e) => {setSelected(selected !== "Template_one" ? "Template_one" : ""); handleSelected(e);}}>
<h1>Template_one</h1>
<table striped bordered hover size="sm">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Job</th>
<th>Facebook</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Mark</td>
<th>Developer</th>
<td>facebook/Mark</td>
</tr>
</tbody>
</table>
</div>
<div className={`template_two ${selected === "Template_two" ? "selected" : "unselected"}`} onClick={(e) => {setSelected(selected !== "Template_two" ? "Template_two" : "");handleSelected(e);}}>
<h1>Template_two</h1>
<table striped bordered hover size="sm">
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Job</th>
<th>Company</th>
<th>Contact </th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>Trump</td>
<th>President</th>
<td>Trump Organization</td>
<td>+1 728 256 345</td>
</tr>
</tbody>
</table>
</div>
</div>
);
}
And here is settings.js
import React from "react";
export default function Settings() {
return (
<div>
<h1>Settings</h1>
<div className="Settings">
<form>
Name: <input type="text" name="firstname" />
Job: <input type="text" name="job" /> <br />
Facebook: <input type="text" name="facebook" />
Company: <input type="text" name="company" />
Contact: <input type="text" name="contact" />
</form>
<div className="selected-template">
Here should be the selected template
</div>
</div>
</div>
);
}
Expected result:
Problem: I don't know how to display the selected templates in the settings component.
How do I copy the selected template to the settings component so that the user can edit the selected template.?
I don't know why but someone deleted my other post that's why I'm seeing your message now. If you want to make different styles you can add classnames to your data. Also if you want, you can look at this libary: https://material-ui.com/styles/basics/ it is so populer around react users. You can basicly make all styles in javascript with this libary. If you gonna use this libary you can add all jss in your data.
here is example:
const table1= {
root: {
background: 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
border: 0,
borderRadius: 3,
boxShadow: '0 3px 5px 2px rgba(255, 105, 135, .3)',
color: 'white',
height: 48,
padding: '0 30px',
},
};
Data=[
{
name:'something',
style:table1
},
{
age:22,
style:table2
}
]
and basic explanation about how to use this styles
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
function Table() {
const classes = props.data.style();
return <Table className={classes.root}>Your table here</Table>;
}
export default withStyles(props.data.style)(Table);

Why am I getting a TypeError when trying to run my code?

I'm trying to figure out why I'm getting Cannot destructure property 'id' of 'this.props.customer' as it is undefined. error. My code seems to be correct from the looks of it but despite this fact, I'm still getting the aforementioned error. Is there something minuscule that I'm overlooking?
Here's CustomerList.js file:
import React, { Component } from "react";
import Customer from "./Customer";
class CustomerList extends Component {
render() {
const customers = this.props.customers;
return(
<div className="data">
<table className="ui celled table">
<thead>
<tr>
<th style={{ width: '50px', textAlign: 'center' }}>#</th>
<th>Name</th>
<th>E-mail</th>
<th style={{ width: '148px' }}>Action</th>
</tr>
</thead>
<tbody>
{
customers.map(customer => {
return <Customer customer={customer} key={customer.id} />;
})
}
<Customer/>
</tbody>
</table>
</div>
);
}
}
export default CustomerList;
Here's Customer.js:
import React, { Component } from 'react';
class Customer extends Component {
render() {
const { id, first_name, last_name, email } = this.props.customer;
return (
<tr>
<td style={{ textAlign: 'center' }}>{id}</td>
<td>{`${first_name} ${last_name}`}</td>
<td>{email}</td>
<td>
<button className="mini ui blue button">Edit</button>
<button className="mini ui red button">Delete</button>
</td>
</tr>
);
}
}
export default Customer;
Below the map part you have a single
<Customer/>
This call to the Customer component has no parameters, so customer is undefined. That is why you get the error.

How to alert out the value of an option box in React?

I would like to get the values of the option boxes. Here's the sample code I wrote. I am trying to populate the option boxes from arrays. I can tell you details if needed for the solution. Thank you for your help in advance!
import React from 'react';
class Scooters extends React.Component {
static defaultProps = {
cat_brand: ['Honda', 'Peugeot', 'Yamaha'],
cat_cc: ['50cc', '125cc', '150cc', '250cc', '300cc'],
cat_price: ['20-70 €', '80-120 €', '130-160 €']
}
btnClick() {
alert('Button has been clicked...');
{/* I would like to alert here the selected options of the boxes. */}
}
render() {
let Brand_categoryOptions = this.props.cat_brand.map(categoryBrand => {
return <option key={categoryBrand} value={categoryBrand}>{categoryBrand}</option>
});
let Cc_categoryOptions = this.props.cat_cc.map(categoryCc => {
return <option key={categoryCc} value={categoryCc}>{categoryCc}</option>
});
let Price_categoryOptions = this.props.cat_price.map(categoryPrice => {
return <option key={categoryPrice} value={categoryPrice}>{categoryPrice}</option>
});
return (
<div>
<div className="container-fluid content">
<h2 className="text-center mt-2">Choose from our Scooters</h2>
<br></br>
<form>
<div class="container col-lg-4 mt-5">
<table class="table table-bordered">
<tr><th>Specifications</th> <th>Set the parameters</th></tr>
<tr><td>Scooter Brand</td> <td><select ref="cat_brand">{Brand_categoryOptions}</select></td></tr>
<tr><td>Engine CC</td> <td><select ref="cat_cc">{Cc_categoryOptions}</select></td></tr>
<tr><td>Unit Price</td> <td><select ref="cat_price">{Price_categoryOptions}</select></td></tr>
<tr><th>Action</th> <th><button onClick={this.btnClick}>Search</button></th></tr>
</table>
</div>
</form>
</div>
</div>
);
}
};
export default Scooters;
You need to add event handler function to select element and store the value in state. Also don’t forget to bind your btnClick function in constructor or use arrow function instead
Below code would work
dropDownChange = e => {
this.setState({
value: e.target.value
});
}
btnClick = () => {
alert('Option selected ', this.state.value);
}
<select ref="cat_price" onChange={this.dropDownChange} value={this.state.value}>{Price_categoryOptions}</select>
Try this. I added an onChange handler on the form which takes the change event, and sets the components state respectively (the state is initialized with a value from your default props, so that if you selected nothing and click it has the default values).
It gets the name attribute on the select element and the value from the event target. And on submit you prevent the default behavior which is the submit, so you can do whatever you want with your data.
class Scooters extends React.Component {
static defaultProps = {
cat_brand: ['Honda', 'Peugeot', 'Yamaha'],
cat_cc: ['50cc', '125cc', '150cc', '250cc', '300cc'],
cat_price: ['20-70 €', '80-120 €', '130-160 €']
}
state = {
cat_brand: this.props.cat_brand[0],
cat_cc: this.props.cat_cc[0],
cat_price: this.props.cat_price[0],
}
onChange = (event) => {
const { name, value } = event.target;
this.setState({ [name]: value })
}
btnClick = (event) => {
event.preventDefault();
console.log(this.state);
}
render() {
let Brand_categoryOptions = this.props.cat_brand.map(categoryBrand => (<option key={categoryBrand} value={categoryBrand}>{categoryBrand}</option>));
let Cc_categoryOptions = this.props.cat_cc.map(categoryCc => (<option key={categoryCc} value={categoryCc}>{categoryCc}</option>));
let Price_categoryOptions = this.props.cat_price.map(categoryPrice => (<option key={categoryPrice} value={categoryPrice}>{categoryPrice}</option>));
return (
<div>
<div className="container-fluid content">
<h2 className="text-center mt-2">Choose from our Scooters</h2>
<br></br>
<form onChange={this.onChange}>
<div className="container col-lg-4 mt-5">
<table className="table table-bordered">
<tbody>
<tr>
<th>Specifications</th>
<th>Set the parameters</th>
</tr>
<tr>
<td>Scooter Brand</td>
<td>
<select name="cat_brand" ref="cat_brand">{Brand_categoryOptions}</select>
</td>
</tr>
<tr>
<td>Engine CC</td>
<td>
<select name="cat_cc" ref="cat_cc">{Cc_categoryOptions}</select>
</td>
</tr>
<tr>
<td>Unit Price</td>
<td>
<select name="cat_price" ref="cat_price">{Price_categoryOptions}</select>
</td>
</tr>
<tr>
<th>Action</th>
<th>
<button onClick={this.btnClick}>Search</button>
</th>
</tr>
</tbody>
</table>
</div>
</form>
</div>
</div>
);
}
};

How to sort API response for some field

I just start to learn Reactjs and have stopped with some question.
I've fetched data through axios for some API endpoint(get countries with some data like population,currencies,region etc.) and I want to sort data for some field(region or population for example).
I thought that in reactjs it will be simple to do and reactjs have some built-in things to do that. But when I've tried to do that and when I've searched answer in google I was really exposed. What is the best way to implement sorting? How can I do that?
What I've tried:
import React, { Component } from 'react';
import axios from 'axios';
import './App.css';
class App extends Component {
constructor(props){
super(props)
this.state={
countries:[],
}
}
componentDidMount(){
axios.get('https://restcountries.eu/rest/v2/all')
.then(response => {
this.setState({
countries:response.data
})
})
.catch((error) => {
console.log("error", error)
})
}
render(){
return(
<div className = 'table'>
<table>
<tbody>
<tr>
<th>Country name </th>
<th>Currencies</th>
<th>Region </th>
<th>Flag </th>
<th >Population</th>
<th>Languages</th>
</tr>
{
this.state.countries.map((country,id) => {
return(
<tr className="tableRow">
<td> {country.name}</td>
<td>{country.currencies.map((currency,i)=>{
return (
<p>
<span>{currency.name} </span>
<span>{currency.symbol} </span>
</p>
)
})} </td>
<td> {country.region}</td>
<td> <img src={country.flag} alt={country.denonym}/> </td>
<td> {country.population} </td>
<td> {country.languages.map((language)=>{
return (
<span> {language.name} </span>
)
})} </td>
</tr>
)
})
}
</tbody>
</table>
</div>
)
}
}
export default App;
Basically what you need to do is something like this:
...
this.state.countries.sort(/* Provide sort function here */).map((country,id) => {
...
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort

add row on button press React

im trying to add a row to a table, on a click event. Here is my component:
import React, { Component } from 'react';
import PageContent from 'components/PageContent';
import { IBox, IBoxTitle, IBoxContent } from 'components/IBox';
import IBoxTools from 'components/IBoxTools';
import Table from 'components/Table';
export default class SalesChannelsPage extends Component {
constructor(props) {
super(props);
this.addRow = this.addRow.bind(this);
}
render() {
return (
<PageContent header="Salgskanaler">
<IBox>
<IBoxTitle>
Salgskanaler
<IBoxTools icon="fa fa-plus" title="Tilføj salgskanal" handleClick={() => this.addRow()}/>
</IBoxTitle>
<IBoxContent>
<Table>
<thead>
<tr>
<td className="channel-name">Navn</td>
<td className="channel-description">Beskrivelse</td>
<td className="channel-btn"></td>
</tr>
</thead>
<tbody>
</tbody>
</Table>
</IBoxContent>
</IBox>
</PageContent>
);
}
addRow() {
console.log('add row')
}
}
So everytime i click the button, a new row should be added, and it should be possible to add as many rows to the list as possible. here is the row i want to add.
i realize that i could make an array in state and just put it there, but i have learned that only the data should be contained in the state. Some help would be much appreciated.
Thx
<tr>
<td className="channel-name">
<input className="form-control input-sm" type="text" placeholder="Navn..." />
</td>
<td className="channel-description">
<input className="form-control input-sm" type="text" placeholder="Beskrivelse..." />
</td>
<td className="channel-btn">
<div>
<div className="btn btn-xs btn-danger"><span className="fa fa-times"></span></div>
<div className="btn btn-xs btn-primary"><span className="fa fa-floppy-o"></span></div>
</div>
</td>
</tr>
So as Matthew Herbst said, this is what state is for. Presumably those rows need to display some kind of data. You shouldn't be storing the HTML/JSX in the array, but you should be storing the data used to construct the list in the array. This is what is great about React. You declare how the UI should be presented based on the underlying data. Then you just manipulate the data. So first you need an array in your state that represents the list. Also, you don't need to declare your addRow handler as being returned by a function. It is a function. Just pass the function without invoking it by excluding the () parentheses. Finally, you map over the array, returning the rows. Obviously this is all kind of dump without data, but it is immediately clear what data you want in the rows. So it should look something like this:
import React, { Component } from 'react';
import PageContent from 'components/PageContent';
import { IBox, IBoxTitle, IBoxContent } from 'components/IBox';
import IBoxTools from 'components/IBoxTools';
import Table from 'components/Table';
export default class SalesChannelsPage extends Component {
constructor(props) {
super(props);
this.addRow = this.addRow.bind(this);
this.state = {
rows: []
}
}
render() {
return (
<PageContent header="Salgskanaler">
<IBox>
<IBoxTitle>
Salgskanaler
<IBoxTools icon="fa fa-plus" title="Tilføj salgskanal" handleClick={this.addRow}/>
</IBoxTitle>
<IBoxContent>
<Table>
<thead>
<tr>
<td className="channel-name">Navn</td>
<td className="channel-description">Beskrivelse</td>
<td className="channel-btn"></td>
</tr>
</thead>
<tbody>
{this.state.rows.map(row => <tr></tr>)}
</tbody>
</Table>
</IBoxContent>
</IBox>
</PageContent>
);
}
addRow() {
var nextState = this.state;
nextState.rows.push('placeholder');
this.setState(nextState);
}
}
Again I am just pushing the text placeholder to the end of the array each time because I don't know what data you want in there. But this will keep generate empty <tr> tags for you on each push of the button.

Categories