Table rows disappearing on going to the next page - javascript

I am new to react. I am using an addrow method to add the values to the table I created using {this.state.rows.map}. The table appears with the values of the input fields. However on pressing the continue button to go to the next page and then coming back from the page by pressing the back button, the row disappears.
Here is the code:
<Grid item xs={10} direction="row" alignItems="center">
<table
className="table table-bordered table-hover"
id="tab_logic"
>
<thead>
{this.state.rows.length > 0 ? (
<tr>
<th className="text-center"> # </th>
<th className="text-center"> KPI </th>
<th className="text-center"> UOM </th>
<th className="text-center"> Base </th>
<th className="text-center"> Target </th>
<th className="text-center"> Target Date </th>
<th className="text-center"> Delete Row </th>
</tr>
) : null}
</thead>
<tbody>
{this.state.rows.map((item, idx) => (
<tr id="addr1" key={idx}>
<td>{idx + 1}</td>
<td>
<input
type="text"
name="Kpi_Before"
defaultValue={Kpi_Before}
onChange={this.handleChangeRows(idx)}
className="form-control"
readOnly
/>
</td>
<td>
<input
type="text"
name="UOM_Before"
defaultValue={UOM_Before}
onChange={this.handleChangeRows(idx)}
className="form-control"
readOnly
/>
</td>
<td>
<input
type="text"
name="Base_Before"
defaultValue={Base_Before}
onChange={this.handleChangeRows(idx)}
className="form-control"
readOnly
/>
</td>
<td>
<input
type="text"
name="Target_Before"
defaultValue={Target_Before}
onChange={this.handleChangeRows(idx)}
className="form-control"
readOnly
/>
</td>
<td>
<input
type="text"
name="dateTime"
defaultValue={dateTime}
onChange={this.handleChangeRows(idx)}
className="form-control"
readOnly
size="38"
/>
</td>
<td>
The code for changes and going back and forward is this:
continue = e => {
e.preventDefault();
this.props.nextStep();
}
};
back = e => {
e.preventDefault();
this.props.prevStep();
};
handleChangeRows = idx => e => {
const { name, value } = e.target;
const rows = [...this.state.rows];
rows[idx] = {
[name]: value
};
this.setState({
rows
});
};
handleAddRow = () => {const item = {
Kpi_Before: [],
UOM_Before: "",
Base_Before: "",
Target_Before: "",
dateTime: "",
rows:[]
};
this.setState({
rows: [...this.state.rows, item]
});
}
};
nextStep = () => {
const { step } = this.state;
this.setState({
step: step + 1
});
};
//Go back to previous step
prevStep = () => {
const { step } = this.state;
this.setState({
step: step - 1
});
};
How do I keep the rows from disappearing and keep it constant on moving back and forward?

Your state re-renders when you navigate between pages or refresh which means everything inside state is lost to combat this you can either:
1) Use redux to store changes and retrieve data from there.
2) Use Context API which is the same as redux but builtin to react.
3) Consume a REST API which means have some sort of backend to store the values and get them on component mount.

Related

checked box need to be click 2 time to make it check i have tried with onclick as well it is giving same behaviour i need to disable button oncheck

**react js **
what I want is when i check any checkbox from the table in the particular button gets disabled but i have to click the checkbox two times to make it check i have also tried with onClick it is also giving the same output Please help me i am get the data through api call form localost only in useEffect and storing the data in a state Array with addon key to make
checkbox checked and button disabled and the state checked is to toggel the value of checkbox and button; But the only problem is User have to click it 2 times i am not able to figure out
const Table1 = () => {
const [supervisors, setSupervisors] = useState([]);
const [checked, setChecked] = useState(false);
useEffect(() => {
const fetchTableList = async () => {
const { data } = await axios("http://localhost:4000/users");
let newData = data.map((item) => {
item.checked = false;
item.disabled = false;
return item;
});
setSupervisors(newData);
};
fetchTableList();
}, []);
console.log(supervisors);
return (
<div className="table-component" style={{ minHeight: "91vh" }}>
<h2 className="main-heading text-center">Supervisor Mapping</h2>
<Table striped bordered hover className="table text-center">
<thead className="heading">
<tr style={{ fontSize: "1.125rem" }}>
<th className="table-heading">OID</th>
<th className="table-heading">Supervisor </th>
<th className="table-heading">Title</th>
<th className="table-heading">Project</th>
<th className="table-heading">Industry</th>
<th className="table-heading">Supervisee</th>
<th className="table-heading">Receiver</th>
<th className="table-heading">Actions</th>
</tr>
</thead>
<tbody>
{supervisors.map((item, index) => (
<tr key={item.supervisorId} style={{ fontSize: "0.938rem" }}>
<td>{item.supervisorId}</td>
<td className="mx-5">{item.supervisor} </td>
<td>{item.title}</td>
<td>{item.project}</td>
<td>{item.industry}</td>
<td
style={
item.supervisee.length > 5
? { backgroundColor: "red", color: "white" }
: item.supervisee.length > 1
? { backgroundColor: "yellowgreen", color: "white" }
: { backgroundColor: "#FFD580", color: "white" }
}
>
{item.supervisee.length}{" "}
</td>
<td>
{" "}
<input
className="checkBox"
type="checkbox"
onChange={() => {
setChecked(!checked);
item.checked = checked;
}}
checked={item.checked}
/>
</td>
<td>
<Button
className="fas fa-eye"
disabled={item.checked}
id={index}
data-id={item.supervisorId}
data-name={item.supervisor}
></Button>
</td>
</tr>
))}
</tbody>
</Table>
</div>
)}
Do not mutate the state directly.
onChange={() => {
setChecked(!checked);
item.checked = checked; //
}}
checked={item.checked}
Always update a clone of the state.
onChange={() => {
// create a clone of the supervisors array
const newSupervisors = supervisors.slice(0);
// mutate the cloned array
newSupervisors[index].checked = !item.checked;
// replace the state with the mutated clone
setSupervisors(newSupervisors);
}}
This is not necessary.
const [checked, setChecked] = useState(false);

React Component keeps re-rendering/reloading

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>

Why is <input type='number' value={var_name}> replacing all the values in a table?

I am trying to map out a number of elements in a table and each of the elements has a specific value. Whenever i use value={inputArrival} or value={inputBurst} all the values of the specific column get update. I am attaching a screenshot. How to fix this?
Screenshot of what's happening
import React,{useState} from 'react';
import './tableEdit.css';
const EntryTable = (props) => {
const entry=props.numOfEntries;
const[inputArrival,SetinputArrival]=useState('');
const[inputBurst,SetinputBurst]=useState('');
function changeArrival(e)
{
console.log(e.target.value+"A");
/*
if(!Number(e.target.value))
return;
else*/
SetinputArrival(e.target.value);
}
function changeBurst(e)
{
console.log(e.target.value+"B");
SetinputBurst(e.target.value);
}
// console.log(entry);
var ArrayEntry=[];
for(var i=1;i<=entry;i++)
ArrayEntry.push( <tr key={i}>
<td className='row_editContent' >P{i}</td>
<td className='row_editContent'><input className='input_edit' placeholder='0' type='number' value={inputArrival} onChange={(e)=>changeArrival(e)}></input>ms</td>
<td className='row_editContent'><input className='input_edit' placeholder='0' type='number' value={inputBurst} onChange={(e)=>changeBurst(e)}></input>ms</td>
</tr>);
return (
<div>
<table className='MainTableContainer' >
<thead>
<tr >
<th className='row_editHeading'>Process</th>
<th className='row_editHeading'>Arrival Time</th>
<th className='row_editHeading'>Burst Time</th>
</tr>
</thead>
<tbody>
{ArrayEntry}
</tbody>
</table>
</div>
)
}
export default EntryTable
You are using the same single states inputArrival and inputBurst for every row entry of data in the table. Update so each is an array of strings, and update the changeArrival and changeBurst callbacks to curry an index to update. Use the mapped index to access the correct state and pass to the onChange callbacks.
const EntryTable = (props) => {
const entry = props.numOfEntries;
const [inputArrival, setInputArrival] = useState(Array(entry).fill(""));
const [inputBurst, setInputBurst] = useState(Array(entry).fill(""));
function changeArrival(index) {
return (e) => {
console.log(e.target.value + "A");
setInputArrival((values) =>
values.map((value, i) => (i === index ? e.target.value : value))
);
};
}
function changeBurst(index) {
return (e) => {
console.log(e.target.value + "B");
setInputBurst((values) =>
values.map((value, i) => (i === index ? e.target.value : value))
);
};
}
// console.log(entry);
const ArrayEntry = Array.from({ length: entry}).map((_, i) => (
<tr key={i}>
<td className="row_editContent">P{i}</td>
<td className="row_editContent">
<input
className="input_edit"
placeholder="0"
type="number"
value={inputArrival[i]}
onChange={changeArrival(i)}
/>
ms
</td>
<td className="row_editContent">
<input
className="input_edit"
placeholder="0"
type="number"
value={inputBurst[i]}
onChange={changeBurst(i)}
/>
ms
</td>
</tr>
));
return (
<div>
<table className="MainTableContainer">
<thead>
<tr>
<th className="row_editHeading">Process</th>
<th className="row_editHeading">Arrival Time</th>
<th className="row_editHeading">Burst Time</th>
</tr>
</thead>
<tbody>{ArrayEntry}</tbody>
</table>
</div>
);
};

How to get all checkbox IDs that are checked using Javascript?

I'm working on a project named "Food Recipes", where a user can create, edit, delete his own recipes.
When creating a new recipe, the user must select the ingrediets.
So here is where I need your help:
By an axios call, I'm getting all the ingredients and show them into a table. The table looks like this:
|---------------------|------------------|-----------------|
| Ingredient | Check | Amount |
|---------------------|------------------|-----------------|
| Tomato | true | 2 kg |
|---------------------|------------------|-----------------|
| Potato | false | |
|---------------------|------------------|-----------------|
| Onion | true | 1 kg |
|---------------------|------------------|-----------------|
After checking some ingredient to TRUE, I want to have onChange function that will create list of IDs, from all ingredients that are CHECKED (in this case, I will have list with two elements: ID from Tomato, and ID from Onion)
To mention, i put ingredient ID as a value inside the <input type="checkbox"/>
Here is my code:
import React, {Component, useEffect, useState} from 'react'
import axios from "../../../axios/axios"
class Ingredient extends Component {
constructor(props){
super(props)
this.state = {
ingredients: [],
ingedientsList: [],
isChecked: false,
}
}
onIngredientChange = (e) => {
//HERE
};
componentDidMount() {
axios.get("/ingredients").then((data) => {
const ingredients = Object.keys(data.data).map((ingredient, index) => {
return (
<tr key={index}>
<td scope="col">
<label>{data.data[index].name}</label>
</td>
<td scope="col">
<input
id={data.data[index].id}
key={index}
type="checkbox"
name={"newIngredients"}
value={data.data[index].id}
onChange={this.onIngredientChange}
/>
</td>
<td scope="col">
<input
id={data.data[index].id + "amount"}
key={index}
type="number"
min="0"
max="500"
name="amount"
placeholder="grams"
onChange={this.onIngredientChange}
/>
</td>
</tr>
);
});
this.setState({ingredients: ingredients});
});
}
render() {
return (
<div className="form-group">
<table className="table tr-history table-striped small">
<thead>
<tr>
<th scope="col">
<h5>Ingredient</h5>
</th>
<th scope="col">
<h5>Check</h5>
</th>
<th scope="col">
<h5>Amount</h5>
</th>
</tr>
</thead>
<tbody>
{this.state.ingredients}
</tbody>
</table>
</div>
)
}
}
export default Ingredient;
Update
Try the code below.
const data = {
data:[
{
id:1,
name:"A"
},
{
id:2,
name:"B"
},
{
id:3,
name:"C"
}
]
}
class Ingredient extends React.Component {
constructor(props){
super(props)
this.state = {
ingredients: [],
ingedientsList: [],
checkedList:[],
isChecked: false,
}
}
componentDidMount() {
const ingredients = data.data.map((ingredient, index) => {
return (
<tr key={index}>
<td scope="col">
<label>{data.data[index].name}</label>
</td>
<td scope="col">
<input
id={data.data[index].id}
key={index}
type="checkbox"
name={"newIngredients"}
value={data.data[index].id}
onChange={(e)=>this.onIngredientChange(e,data.data[index].id)}
/>
</td>
<td scope="col">
<input
id={data.data[index].id + "amount"}
key={index}
type="number"
min="0"
max="500"
name="amount"
placeholder="grams"
onChange={this.onIngredientChange}
/>
</td>
</tr>
);
});
this.setState({ingredients: ingredients});
}
onIngredientChange = (e,id) => {
let resultArray = []
if(e.target.checked) //if checked (true), then add this id into checkedList
{
resultArray = this.state.checkedList.filter(CheckedId=>
CheckedId !== id
)
resultArray.push(id)
}
else //if not checked (false), then remove this id from checkedList
{
resultArray = this.state.checkedList.filter(CheckedId=>
CheckedId !== id
)
}
console.log(resultArray)
this.setState({
checkedList:resultArray
})
}
render() {
return (
<div className="form-group">
<table className="table tr-history table-striped small">
<thead>
<tr>
<th scope="col">
<h5>Ingredient</h5>
</th>
<th scope="col">
<h5>Check</h5>
</th>
<th scope="col">
<h5>Amount</h5>
</th>
</tr>
</thead>
<tbody>
{this.state.ingredients}
</tbody>
</table>
</div>
)
}
}
// Render it
ReactDOM.render(
<Ingredient />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="react"></div>
First, have a checked list in state
this.state = {
ingredients: [],
ingedientsList: [],
checkedList:[]
isChecked: false,
}
Then change element a little bit,
<input
id={data.data[index].id}
key={index}
type="checkbox"
name={"newIngredients"}
value={data.data[index].id}
onChange={(e)=>this.onIngredientChange(e,data.data[index].id)}
/>
Then change handler,
onIngredientChange = (e,id) => {
let resultArray = []
if(e.target.checked) //if checked (true), then add this id into checkedList
{
resultArray = this.state.checkedList.filter(CheckedId=>
CheckedId !== id // filter(checkID=>{CheckedId !== id}) remove {}
)
resultArray.push(id)
}
else //if not checked (false), then remove this id from checkedList
{
resultArray = this.state.checkedList.filter(CheckedId=>
CheckedId !== id // filter(checkID=>{CheckedId !== id}) remove {}
)
}
this.setState({
checkedList:resultArray
})
console.log(resultArray) // get all checked ID
};
Try this. Use a state array instead of simple array.
onIngredientChange = (e, value) => {
if (array.includes(value) && !e.target.checked) {
array.splice( array.indexOf(value), 1 );
} else if (!array.includes(value) && e.target.checked) {
array.push(value)
}
};
<input id={data.data[index].id} key={index}
type="checkbox" name={"newIngredients"}
value={data.data[index].id}
onChange={(e) =>this.onIngredientChange(e, value)} />
...
onIngredientChange = e => {
const checkedIngrediants = {
...this.state.checkedIngrediants
[e.target.id]: !e.target.value
};
this.setState({
checkedIngredients,
ingredientsList: Object.keys(checkedIngredients)
.filter(key => checkedIngredients[key])
})
}
...
<input
id={data.data[index].id}
key={index}
type="checkbox"
name={"newIngredients"}
value={this.state.checkedIngrediants[data.data[index].id]}
onChange={this.onIngredientChange} />

How to work with multiple inputs fields with .map - ReactJS

I have an assignment to make cryptocurrenty converter using API from coinmarketcap. I have manage to retrieve data and show everything but problem is that all fields act like one field.
You can see it here:
https://repl.it/repls/IncompatibleWhirlwindHarddrive
function App() {
const [data, setData] = useState("");
const [coinValue, setCoinValue] = useState("")
const [value, setValue] = useState("")
useEffect(() => {
let url = "https://cors-anywhere.herokuapp.com/https://sandbox-api.coinmarketcap.com/v1/cryptocurrency/listings/latest"
axios
.get(url,{
headers: {
'X-CMC_PRO_API_KEY': 'c8643baa-31bf-4d31-8868-af73ce84766b'
},
})
.then(result => setData(result.data.data));
}, []);
return (
<>
<table className="table ">
<thead>
<tr>
<th>Name</th>
<th>Short Name</th>
<th>$ Value</th>
<th>Last 24h</th>
<th>Amount you own</th>
<th>$ value of your coins</th>
</tr>
</thead>
<tbody>
{Array.isArray(data) &&
data.map(objects => {
let price = objects.quote.USD.price.toFixed(2)
let Result = (function() {
return price * coinValue
});
return (
<tr key={objects.name}>
<td>{objects.name}</td>
<td>
{objects.symbol}
</td>
<td onLoad={()=>setValue(price)}>
{price}
</td>
<td style={{color: objects.quote.USD.percent_change_24h > 0 ? "green" : "red"}}>{objects.quote.USD.percent_change_24h.toFixed(2)}</td>
<td>
<input required type="number" onChange={e => setCoinValue(e.target.value)} /> <br/>
<button className="btn" disabled={!coinValue} type="submit" onClick={Result}>Submit</button>
</td>
<td>
<Result></Result>
</td>
</tr>
);
})}
</tbody>
</table>
</>
);
}
export default App;
I need to every button be disabled until there is some value in input field but on input field that goes with that button.
Also I have to show conversion for only that field that input has value when you press submit.
Thank you in advance.

Categories