I'm unfamiliar with React and would appreciate some help. I have a table within a form where each row is a project that has a status (either 'Pending Approval' or 'Approved'). I also have a checkbox in each row. I would like it so that when the checkbox next to a row is selected and the form is submitted, I can change the status of each selected project to 'Approved.'
<Form>
<FormGroup>
<Button type="submit" onClick {this.submitClicked}>Approve Projects</Button>
</FormGroup>
<Table bordered={true}>
<thead>
<tr>
<th>Select</th>
<th>Project Name</th>
<th>Project Number</th>
<th>Project Status</th>
<th>Min Size</th>
<th>Max Size</th>
</tr>
</thead>
<tbody>
{projects.map((project: Project) =>
<tr key={project.projectNumber}>
<td>
<FormControl
type="checkbox"
id="selected"
value={project.projectName}
onChange={e => this.handleChange(e)}
/>
</td>
<td>{project.projectName}</td>
<td>{project.projectNumber}</td>
<td>{project.status}</td>
<td>{project.minSize}</td>
<td>{project.maxSize}</td>
</tr>
)}
</tbody>
</Table>
</Form>
What should go in my handleChange function and how should I go about doing this? I was wondering if there was some way to add the selected projects to an array and then change their status value?
You can use components with state. That allows you to manage a state inside a component. Thus you can manipulate it and change the projects' statuses in your example. More about this here: state classes
Example:
class YourComponent extends React.Component {
constructor(props) {
super(props);
this.state = {projects: props.projects};
}
handleChange = (e) => {
let projects = this.state.projects;
// manipulate your project here
this.setState({
projects: projects
});
}
render(){
return (<Form>
(...)
</Form>)
}
}
Related
This question already has an answer here:
List elements not rendering in React [duplicate]
(1 answer)
Closed 23 days ago.
I have a react component that is supposed to take an array of items passed to the component as a prop and render a table. I have done this successfully with another component already. Yet for some reason, the table does not want to populate rows in this component.
Here is the component that renders the :
class OrderList extends React.Component {
constructor(props) {
super(props);
this.populateTable = this.populateTable.bind(this);
}
populateTable() {
return this.props.orders.map((order) => {
<tr key={order.id}>
<td>{order.orderNo}</td>
<td>{order.customer.name}</td>
<td>{order.customerPO}</td>
<td>{order.orderDate}</td>
<td>{order.shipDate}</td>
</tr>
});
}
render() {
return(
<Table striped bordered hover>
<thead>
<tr>
<td>Order No.</td>
<td>Customer Name</td>
<td>Customer P.O.</td>
<td>Order Date</td>
<td>Ship Date</td>
</tr>
</thead>
<tbody>
{this.populateTable()}
</tbody>
</Table>
);
}
}
Using react dev tools, I can see that the orders prop does contain the correct data, and array of objects. I can even throw in a console.log line within the forEach loop, so I know the component is actually looping over the data. However, no rows are rendered?
Your map is not returning anything this is the reason
class OrderList extends React.Component {
constructor(props) {
super(props);
this.populateTable = this.populateTable.bind(this);
}
populateTable() {
return this.props.orders.map((order) => (
<tr key={order.id}>
<td>{order.orderNo}</td>
<td>{order.customer.name}</td>
<td>{order.customerPO}</td>
<td>{order.orderDate}</td>
<td>{order.shipDate}</td>
</tr>
));
}
render() {
return(
<Table striped bordered hover>
<thead>
<tr>
<td>Order No.</td>
<td>Customer Name</td>
<td>Customer P.O.</td>
<td>Order Date</td>
<td>Ship Date</td>
</tr>
</thead>
<tbody>
{this.populateTable()}
</tbody>
</Table>
);
}
}
when you use curly braces in map you have to use return keyword to return anything
in order to return from your method you can try something like this
populateTable() {
return this.props.orders.map((order) => {
return (<tr key={order.id}>
<td>{order.orderNo}</td>
<td>{order.customer.name}</td>
<td>{order.customerPO}</td>
<td>{order.orderDate}</td>
<td>{order.shipDate}</td>
</tr>)
});
}
I am new to React currently doing my first react project. I can't figure out the issue here. Below is my code. User is redirected from another page to this page when they entered their search team and click search.
const Result = () => {
const navigate = useNavigate();
const [routes, setRoutes] = useState([]);
const { from, destination } = useParams();
const [departureLocation, setDepartureLocation] = useState(from);
const [destinationLocation, setDestinationLocation] = useState(destination);
const onSubmit = (e) => {
e.preventDefault();
navigate('/result/' + departureLocation + '/' + destinationLocation);
};
useEffect(() => {
refreshRoutes();
}, []);
const refreshRoutes = () => {
API.get("routes/")
.then((res) => {
setRoutes(res.data);
})
};
return (
<div className = "container mt-5">
< div className = "row" >
<div className="col-md-4">
<Form onSubmit={onSubmit} className="mt-4">
<Form.Group className="mb-3" controlId="formBasicGenre">
<Form.Label>Departure Location</Form.Label>
<Form.Control as="select"
value={departureLocation}
onChange={(e) => setDepartureLocation(e.target.value)}>
<option value="jajarkot">Jajarkot</option>
</Form.Control>
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicStarring">
<Form.Label>Destination Location</Form.Label>
<Form.Control as="select"
placeholder="Enter Destination Location"
value={destinationLocation}
onChange={(e) => setDestinationLocation(e.target.value)}>
<option value="palpa">Palpa</option>
</Form.Control>
</Form.Group>
</Form>
</div>
<div className="col-md-8 m">
<table className="table">
<thead>
<tr>
<th className="table-light" scope="col">ID</th>
<th className="table-light" scope="col">Company Name</th>
<th className="table-light" scope="col">Departure</th>
<th className="table-light" scope="col">Destination</th>
<th className="table-light" scope="col">Departure</th>
<th className="table-light" scope="col">Arrival</th>
<th className="table-light" scope="col">Departure Date</th>
<th className="table-light" scope="col">Price</th>
</tr>
</thead>
<tbody>
{routes.map((route, index) => {
return (
route.departureLocation === from && route.destinationLocation === destination ?
<tr key="">
<th className="table-light" scope="row">{route.vehicleID}</th>
<td className="table-light"> {route.name}</td>
<td className="table-light"> {route.destinationLocation}</td>
<td className="table-light"> {route.departureLocation}</td>
<td className="table-light"> {route.departureTime}</td>
<td className="table-light"> {route.arrivalTime}</td>
<td className="table-light"> {route.departureDate}</td>
<td className="table-light"> {route.price}</td>
</tr>
: null
);
})}
</tbody>
</table>
</div>
</div>
</div>
);
};
When it is redirected to result page as /result/kathmandu/gulmi it does shows the data that matches the parameter. But whenever I click on the dropdown option, the filtered data is appended in the table. I can't figure out whats causing the issue.
The only overt issue I see in your code is the React key used for the table data you are mapping. You are using the same key (key="") for each table row. You should actually be seeing tons of React warnings about duplicate keys. The issue here is that when rendering lists/arrays React uses the key in the reconciliation process, and if the key doesn't change then React bails on rerendering. As you append data to your table React can't invalidate what it previously rendered and it remains on the screen.
See Lists & Keys for more details.
The solution is to use a unique React key per table row, intrinsic id properties, like vehicleID, make for great React keys.
I suggest also running the routes array through a filter first, then mapping, it'll save the conditional rendering.
Example:
<tbody>
{routes.filter((route) =>
route.departureLocation === from && route.destinationLocation === destination
)
.map((route) => (
<tr key={route.vehicleID}>
<th className="table-light" scope="row">{route.vehicleID}</th>
<td className="table-light">{route.name}</td>
<td className="table-light">{route.destinationLocation}</td>
<td className="table-light">{route.departureLocation}</td>
<td className="table-light">{route.departureTime}</td>
<td className="table-light">{route.arrivalTime}</td>
<td className="table-light">{route.departureDate}</td>
<td className="table-light">{route.price}</td>
</tr>
)
)}
</tbody>
I am new to react,and making app where I want to get data of the row being clicked on a table,I don't whether this approach is good or not need suggestions
So far i have used onClick listener but when I click on a table , it gives me [object,object] in console.log(contract),I have also tried to to use loop to view data in it but it gives me [object,object],here's my below code:
<table id="mytable" cellSpacing="0" width="100%">
<thead>
<tr>
<th>CarName</th>
<th>DriverName</th>
<th>Date</th>
<th>Pickup</th>
</tr>
</thead>
<tbody>
{
this.state.contracts.map((contract,index)=>{
return(
<tr key={index} data-item={contract} onClick={this.contractdetails}>
<td>{contract.car} </td>
<td>{contract.driver}</td>
<td>{contract.date}</td>
<td>{contract.pickup}</td>
</tr>
)})
}
</tbody>
</table>
onClickfunction
contractdetails=(e)=>{
const contract=e.currentTarget.getAttribute('data-item');
console.log(contract)
};
Use JSON.stringify while setting the data-item
<tr key={index} data-item={JSON.stringify(contract)} onClick={this.contractdetails}>
And use JSON.parse() while accessing it.
contractdetails=(e)=>{
const contract= JSON.parse(e.currentTarget.getAttribute('data-item'));
console.log(contract)
};
A better way is to just set index as data-index and you can access it from the state
this.state.contracts.map((contract,index)=>{
return(
<tr key={index} data-index={index} onClick={this.contractdetails}>
...
...
}
You can access it like below
contractdetails=(e)=>{
let index = +e.currentTarget.getAttribute('data-index')
console.log(this.state.contracts[index]);
};
I cant display array object in map function. Could someone please tell me why ? When Im trying to display this object in the console I see it correctly.
class ProductsGrid extends React.Component {
constructor(props) {
super(props);
}
render() {
return (<Table striped bordered condensed hover>
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Description</th>
<th>Url</th>
</tr>
</thead>
<tbody>
{this.props.products !== null ?
JSON.parse(this.props.products).map((product, index) => {
<tr>
{console.log(product.IdProduct)}
<td>{product.IdProduct}</td>
<td>{product.Name}</td>
<td>{product.Description}</td>
<td>{product.UrlFriendlyName}</td>
</tr>
}) : <tr><td></td><td></td><td></td><td></td></tr>}
</tbody>
</Table>);
}}
Your map function needs a return statement.
I try to call a parent function from a child function.
I follow this example :Expose Component Functions but with this code my page does not load and my console is empty so i do not know find the problem.
I use webpack with babel and webpack-dev-server
Thank you for your answers.
I am sorry for my english.
class Row extends React.Component {
render(){
return(
<tr className="animated slideInRight">
<th scope="row">{this.props.data.ville_id}</th>
<td>{this.props.data.ville_nom}</td>
<td>{this.props.data.ville_nom_reel}</td>
<td>{this.props.data.ville_canton}</td>
<td><button className="btn btn-success" onClick={this.props.onClick} >Full Detail</button></td>
</tr>
)
}
}
export default class Metier extends React.Component {
constructor() {
super();
this.state = {
data: [],
};
}
deleteClick(e){
console.log("ici")
}
render(){
return(
<table className="table table-striped">
<thead>
<tr>
<th>IdVille</th>
<th>First Name</th>
<th>Last Name</th>
<th>Username</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{this.state.data.map(function(result,i){
var boundClick = this.deleteClick.bind(this,i)
return(
<Row onClick={boundClick} key={i} data={result} />
)
})}
</tbody>
</table>
)
}
}
You have to use the arrow function in the map so you can access this:
{this.state.data.map((result,i) => {
var boundClick = this.deleteClick.bind(this,i)
return(
<Row onClick={boundClick} key={i} data={result} />
)
})}
By using a simple function you create a new context and in that function you cannot access this.deleteClick. Using an arrow function you can still access it.