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

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.

Related

react get data and render it in a modal

I'm trying to get data of a table to modal, I got a table and all data are populated just fine, I got a button next to each row where I will like that when I click the button I display all data from the selected row. I got to manage to get the data with console.log, but I cannot get it to render in the modal. I got no errors but still it doesn't show either. I've attached an image with what i got. as you in the console. I get the select row
customsite.jsx
import React, { useState } from 'react';
import Modal from './reusable/modal';
import useFetchData from './hooks/useFetchData';
const Customsite = ()=> {
const {
data,
loading,
} = useFetchData();
const [display, openModal] = useState(false);
const closeModal = () =>{
openModal(false);
}
const openedModal = () =>{
openModal(true);
}
const getAllData = (data) =>{
console.log(data);
return data;
}
return(
<div>
<div className='conatiner'>
<table className="table">
<thead>
<tr>
<th>id</th>
<th>titel</th>
<th>body</th>
<th>actions</th>
<th>details</th>
</tr>
</thead>
<tbody>
{data.map(posts =>(
<tr key={posts.id}>
<th>{posts.id}</th>
<th>{posts.title}</th>
<th>{posts.body}</th>
<th><button className="btn btn-primary"
onClick={()=> { getAllData(posts); openedModal();}}>
button</button>
</th>
<th>
<button
className="btn btn-success">Success</button>
</th>
</tr>
))}
</tbody>
</table>
<Modal isOpened={display}
closeModal ={closeModal} >
<h1>modal header</h1>
<p>{getAllData}</p>
</Modal>
</div>
</div>
)
}
export default Customsite
Here getAllData is a function that holds the value of the data so by directly calling that inside the <p> tag it will not print the data.
import React, { useState } from 'react';
import Modal from './reusable/modal';
import useFetchData from './hooks/useFetchData';
const Customsite = ()=> {
const {
data,
loading,
} = useFetchData();
const [display, openModal] = useState(false);
const [seletcedData, setSelectedData] = useState();
const closeModal = () =>{
openModal(false);
}
const openedModal = () =>{
openModal(true);
}
const getAllData = (data) =>{
console.log(data);
setSelectedData(data);
openedModal();
}
return(
<div>
<div className='conatiner'>
<table className="table">
<thead>
<tr>
<th>id</th>
<th>titel</th>
<th>body</th>
<th>actions</th>
<th>details</th>
</tr>
</thead>
<tbody>
{data.map(posts =>(
<tr key={posts.id}>
<th>{posts.id}</th>
<th>{posts.title}</th>
<th>{posts.body}</th>
<th><button className="btn btn-primary"
onClick={()=> { getAllData(posts);}}>
button</button>
</th>
<th>
<button
className="btn btn-success">Success</button>
</th>
</tr>
))}
</tbody>
</table>
{display &&
<Modal isOpened={display}
closeModal ={closeModal} >
<h1>modal header</h1>
<p>{selectedData?.title}</p>
</Modal>
}
</div>
</div>
)
}
export default Customsite
Here is the solution and you can create multiple <p> tags to display the required data.
make a state for data
const [tableData, setTableData] = useState({})
after fetching data :
const getAllData = (data) =>{
setTableData(data)
console.log(data);
}
then on Modal:
<Modal isOpened={display}
closeModal ={closeModal} >
<h1>{tableData.title}</h1>
<p>{tableData.body}</p>
</Modal>
Try like this
import React, { useState } from "react";
import Modal from "./reusable/modal";
import useFetchData from "./hooks/useFetchData";
const Customsite = () => {
const { data, loading } = useFetchData();
const [display, openModal] = useState(false);
const [rowData, setRowData] = useState();
const closeModal = () => {
openModal(false);
};
const openedModal = () => {
openModal(true);
};
return (
<div>
<div className="conatiner">
<table className="table">
<thead>
<tr>
<th>id</th>
<th>titel</th>
<th>body</th>
<th>actions</th>
<th>details</th>
</tr>
</thead>
<tbody>
{data.map((posts) => (
<tr key={posts.id}>
<th>{posts.id}</th>
<th>{posts.title}</th>
<th>{posts.body}</th>
<th>
<button
className="btn btn-primary"
onClick={() => {
setRowData(posts);
openedModal();
}}
>
button
</button>
</th>
<th>
<button className="btn btn-success">Success</button>
</th>
</tr>
))}
</tbody>
</table>
<Modal isOpened={display} closeModal={closeModal}>
<div>
<h1>modal header</h1>
<table className="table">
<thead>
<tr>
<th>id</th>
<th>titel</th>
<th>body</th>
</tr>
</thead>
<tbody>
{
<tr key={rowData?.id}>
<th>{rowData?.id}</th>
<th>{rowData?.title}</th>
<th>{rowData?.body}</th>
</tr>
}
</tbody>
</table>
</div>
</Modal>
</div>
</div>
);
};
export default Customsite;

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>
);
};

I'm trying to put the data I'm receiving from my API into a table but nothing is displayed

I'm getting data from my API, when I make a console.log or JSON.stringify in the API data it shows without problems but when I pass the data in a table with the map, simply nothing is presented in the table. .
const [users, setUsers] = useState([]);
const loadUser = () => {
getUsers().then(data => {
if(data.error) {
console.log(data.error)
}else{
setUsers(data)
}
})
}
const inforUsers = () => {
return(
<Fragment>
<table className="table table-bordered mb-5">
<thead className="thead-dark">
<tr>
<th scope="col">Id</th>
<th scope="col">Nome</th>
<th scope="col">Email</th>
<th scope="col">role</th>
<th scope="col">createdAt</th>
</tr>
</thead>
<tbody scope="row">
{Object.keys(users).map((values, key) => (
<tr key={key}>
<td>
{values._id}
</td>
<td>
{values.name}
</td>
<td>
{values.email}
</td>
<td>
{values.role === 1? 'Admin' : 'Simples User'}
</td>
<td>
{values.createdAt}
</td>
</tr>
))}
</tbody>
</table>
</Fragment>
)
}
I think you are confused about the data you have in hand. The key is the id for each object, so if you want that data, you should access the users object by each of the keys/ids you get from Object.keys. A brief example:
{Object.keys(users).map(id => (
{users[id]._id}
))}

Table rows disappearing on going to the next page

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.

Categories