how to fetch api data using react js - javascript

At what i am trying to do is when i click on checkbox 1st row in table and then click submit button then url image is not open .
i want to make when i click on checkbox then click submit button then url image is open.
how can we do that any idea or help its very thankful.
my code https://codepen.io/svpan/pen/NWdJvmX?editors=1010
let ref = null;
class TableComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedRow: ""
};
ref = this;
}
handleRowClick = async (rowID) => {
// make an API call here, sth like
console.log(rowID);
if (rowID) {
const url1 =
"https://mocki.io/v1/b512f8b8-64ab-46e4-9e0c-9db538a0ad9e?id=" + rowID;
// const url2 =
// "https://grandiose-mulberry-garnet.glitch.me/params/" + rowID;
// const url = "https://mocki.io/v1/4d51be0b-4add-4108-8c30-df4d60e8df54";
// you can use any of the above API to test.
const response = await fetch(url1);
const res = await response.json();
// console.log(res)
this.setState({
...res
});
window.open(res.url, "_blank");
}
};
onSelectChange = (rowId) => {
this.setState({
selectedRow: rowId
});
};
render() {
var dataColumns = this.props.data.columns;
var dataRows = this.props.data.rows;
var tableHeaders = (
<thead>
<tr>
{" "}
{dataColumns.map(function (column) {
return <th> {column} </th>;
})}{" "}
</tr>{" "}
</thead>
);
var tableBody = dataRows.map((row) => {
return (
<tr key={row.id}>
{dataColumns.map(function (column) {
if (column == "Select")
return (
<td>
<input
type="checkbox"
checked={ref.state.selectedRow === row.id}
onChange={() => ref.onSelectChange(row.id)}
/>
</td>
);
else
return (
<td>
<a target="_blank" rel="noopener noreferrer" href={row.url}>
{row[column]}
</a>
</td>
);
})}
</tr>
);
});
// Decorate with Bootstrap CSS
return (
<div>
<table className="table table-bordered table-hover" width="100%">
{tableHeaders} {tableBody}
</table>
<input
type="submit"
value="submit"
onClick={() => this.handleRowClick(this.state.selectedRow)}
/>
</div>
);
}
}
// Example Data
var tableData = {
columns: ["Select", "Service_Name", "Cost/Unit"],
rows: [
{
Service_Name: "airplan",
"Cost/Unit": 50,
id: 1
},
{
Service_Name: "cat",
"Cost/Unit": 50,
id: 2
},
{
Service_Name: "fruits",
"Cost/Unit": 50,
id: 5
},
{
Service_Name: "pool",
"Cost/Unit": 50,
id: 4
}
]
};
ReactDOM.render(
<TableComponent data={tableData} />,
document.getElementById("table-component")
);

handleRowClick = async (rowID) => {
// make an API call here, sth like
console.log(rowID);
if (rowID) {
const url1 =
"https://mocki.io/v1/b512f8b8-64ab-46e4-9e0c-9db538a0ad9e?id=" + rowID;
// const url2 =
// "https://grandiose-mulberry-garnet.glitch.me/params/" + rowID;
// const url = "https://mocki.io/v1/4d51be0b-4add-4108-8c30-df4d60e8df54";
// you can use any of the above API to test.
const response = await fetch(url1);
const res = await response.json();
// alert(res.url)
console.log(res)
console.log("row id " + rowID)
let object_ = {};
res.map(item=>{
// console.log(item.url)
if(item.id === rowID){
object_ = item;
}
})
this.setState({
...res
});
window.open(object_.url, "_blank");
}
};

Related

how to read csv file using html file input and convert it into JSON format in react

This is the code I want to optimize the csv to json convertion and file reading in react, it is very slow sometimes. Ignore all the other functionalities.
please look into handleFileChange , handleparseAndSend functions.
What these functions will do is uploading the file and set the data into file variable and then we convert the file into json and we are sending the json file to the backend nodejs.
import React, { useEffect } from "react";
import { useState } from "react";
import { CSVLink } from "react-csv";
//import Papa from "papaparse";
import { useNavigate } from "react-router-dom";
import { toast } from "react-toastify";
import "./app.css";
import "./add.css";
import Headers from "../Utils/Headers";
const allowedExtensions = ["csv"];
function ImportCandidate() {
const [rowData, setRowData] = useState([]);
const [columnDefs, setColumnDefs] = useState([
"candidate_name",
"email",
"contact",
"pan",
"role",
"it_experience_years",
]);
const [t, setT] = useState([]);
const [rec, setRec] = useState([]);
const [dataa, setDataa] = useState([]);
const [error, setError] = useState("");
const [file, setFile] = useState("");
const [fileName, setFileName] = useState(
"Select File to import candidates",
);
const history = useNavigate();
function cancel() {
history("/candidate");
datafetch = [];
}
let datafetch = [],
res,
dfl = [];
const postData = async (parsedData) => {
res = await fetch(
"http://localhost:7000/postmultiple",
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
data: parsedData,
}),
},
);
datafetch = await res.json();
// let msg = JSON.stringify(datafetch);
setRowData(datafetch);
console.log("res status :", res.status);
if (res.status === 500) {
//window.alert(`Invalid Registration ${msg}`);
toast.error("Invalid Registration");
console.log("Invalid Registration");
} else {
console.log(
"----------inside else------rowdata",
JSON.stringify(rowData),
);
if (JSON.stringify(rowData) === JSON.stringify([])) {
toast.success("Registration Successfull");
} else {
toast.success("duplicates are present");
}
// toast.success(JSON.stringify(rowData));
console.log("Registration Sucessfull");
}
};
useEffect(() => {
console.log("rowData!");
console.log({ rowData });
}, [rowData]);
const handleFileChange = (e) => {
setError("");
if (e.target.files.length) {
const inputFile = e.target.files[0];
const fileExtension = inputFile?.type.split("/")[1];
if (!allowedExtensions.includes(fileExtension)) {
setError("Please input a csv file");
return;
}
setFile(inputFile);
setFileName(inputFile.name);
}
};
let invalidData = []
const handleParseAndSend = () => {
console.log(
"---------------start-1--------------------",
);
function csvJSON(csv) {
//------------------validations-------------------------------
function validateName(name) {
const regex = /^[A-Za-z0-9 ]+$/;
return regex.test(name);
}
function validatePAN(pan) {
let regex = /^([a-zA-Z]){5}([0-9]){4}([a-zA-Z]){1}?$/;
return regex.test(pan);
}
function validateContact(contact) {
if (!(/^\d{10}$/).test(contact)) {
return false
} else {
return true
}
}
function validateEmail(email) {
const re = /^(([^<>()[\]\\.,;:\s#"]+(\.[^<>()[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(String(email).toLowerCase());
}
function validateExperience(experience) {
return parseFloat(experience) <= 0;
}
//----------------------------------------
//console.log(csv)
let lines = csv.split("\n");
let result = [];
// NOTE: If your columns contain commas in their values, you'll need
// to deal with those before doing the next step
// (you might convert them to &&& or something, then covert them back later)
// jsfiddle showing the issue https://jsfiddle.net/
let headers = lines[0].trim("\n").split(",");
const nx = lines.length;
const hl = headers.length;
for (let i = 1; i < nx; ++i) {
if (!lines[i]) continue;
var obj = {};
var currentline = lines[i].trim("\n").split(",");
console.log(
"current line ---------------------;;;;;;;;;;;;;;",
currentline,
);
let flag = true;
for (let j = 0; j < hl; ++j) {
let current = currentline[j];
if(j===0) { //name
current = current[0].toUpperCase() + current.substring(1);
if(!validateName(current)) flag=false;
}
else if(j===1) { //email
current = current.toLowerCase();
if(!validateEmail(current)) flag=false;
}
else if(j==2) { //contact
if(!validateContact(current)) flag = false;
}
else if(j===3) { //pan
current = current.toUpperCase();
if(!validatePAN(current)) flag =false;
}
else if(j===4) { //role
}
else if(j===5) {
if(!validateExperience(current)) flag = false;
}
else {
}
obj[headers[j]] = current;
}
if(flag==true)
result.push(obj);
else {
invalidData.push(obj);
flag=true;
}
}
return result; //JavaScript object
}
console.log("Hello psend");
if (!file) return setError("Enter a valid file");
const reader = new FileReader();
reader.onload = async ({ target }) => {
console.log("--------------start-2-----------------");
let parsedData = csvJSON(target.result);
// console.log(parsedData);
parsedData = parsedData.filter((item) => {
if (item.candidate_name.length) {
return true;
}
return false;
});
console.log("This is parsed data ",parsedData);
setDataa([
"candidate_name",
"email",
"contact",
"pan",
"role",
"it_experience_years",
]);
await postData(parsedData);
console.log(
"--------------end-2---------------------",
);
};
reader.readAsText(file);
console.log(
"----------------end-1----------------------",
);
};
const data = [
{
candidate_name: "",
email: "",
contact: "",
pan: "",
role: "",
it_experience_years: "",
},
];
const headers = [
{ label: "candidate_name", key: "candidate_name" },
{ label: "email", key: "email" },
{ label: "contact", key: "contact" },
{ label: "pan", key: "pan" },
{ label: "role", key: "role" },
{
label: "it_experience_years",
key: "it_experience_years",
},
];
const csvTemplate = {
filename: "Template.csv",
headers: headers,
data: data,
};
console.log("xxxxxxxxxxxx datafetch", rowData);
//const rr = rowData?.map(val=> { rowData.candidate_name})
for (let i = 0; i < datafetch.length; ++i) {
dfl.push(i);
}
//const d = [{candidate_name:"vasu", email:"abc#gmail.com", contact : "7689876543", pan:"HGFDT6543R", role:"AES-FED-MEAN", it_experience_years:"2"}]
return (
<div className='wrapper'>
<Headers />
<div className='p-3'>
<div className='row'>
<span className='content1'>
<h2> Import Candidates</h2>
</span>
<div className='col-md-11 my-2 mx-auto text-right d-grid gap-2 d-md-flex justify-content-md-end'>
<div className='btn btn-primary btn-sm float-end py-2'>
<CSVLink
{...csvTemplate}
id='download_template'>
Download Template
</CSVLink>
</div>
</div>
<div className=''>
<span>
<b>Select File</b>
<input
id='file-input'
className='content6'
type='file'
placeholder='Select File to import Candidates'
onChange={handleFileChange}
/>
<label
for='file-input'
id='file-ip-label'
className='col-sm-2 col-form-label fw-lighter ms-5'>
<div id='file-input-label'>
<span>{fileName} </span>
<div style={{ float: "right" }}>
<svg
xmlns='http://www.w3.org/2000/svg'
width='16'
height='16'
fill='currentColor'
className='bi bi-upload'
viewBox='0 0 16 16'>
<path d='M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5z' />
<path d='M7.646 1.146a.5.5 0 0 1 .708 0l3 3a.5.5 0 0 1-.708.708L8.5 2.707V11.5a.5.5 0 0 1-1 0V2.707L5.354 4.854a.5.5 0 1 1-.708-.708l3-3z' />
</svg>
</div>
</div>
</label>
</span>
<span className='content3'>
<button
className='btn btn-primary btn-xl '
onClick={handleParseAndSend}>
Upload File
</button>
</span>
<span>{" "}</span>
<span className='content4'>
<button
className='btn btn-primary btn-xl'
onClick={cancel}>
{" "}
Cancel
</button>
</span>
<div style={{ marginTop: "3rem" }}>
{error
? error
: dataa.map((col, idx) => (
<div key={idx}></div>
))}
</div>
</div>
</div>
{/* </div> */}
<div>
{Array.isArray(rowData) && rowData.length > 0 ? (
<table
className='table table-striped table-responsive'
style={{ paddingLeft: "5px" }}>
<thead>
<h4>Duplicate Data</h4>
<tr>
<th
scope='col'
className=''>
Name
</th>
<th
scope='col'
className=''>
Email
</th>
<th
scope='col'
className='w-15'>
Contact
</th>
<th
scope='col'
className='table_pan'>
PAN
</th>
<th
scope='col'
className='table_role px-3'>
Role
</th>
<th
scope='col'
className='table_exp'>
Experience
</th>
</tr>
</thead>
<tbody>
{Array.isArray(rowData) &&
rowData?.map((row) => (
<tr className='table_padding'>
<td
scope='col'
className=''>
{row.candidate_name}
</td>
<td
scope='col'
className=''>
{row.email}
</td>
<td
scope='col'
className=''>
{row.contact}
</td>
<td
scope='col'
className='table_pan '>
{row.pan}
</td>
<td
scope='col'
className='table_role px-3'>
{row.role}
</td>
<td
scope='col'
className='table_exp px-4 '>
{row.it_experience_years}
</td>
</tr>
))}
</tbody>
</table>
) : null}
</div>
</div>
</div>
);
}
export default ImportCandidate;

How can I display changes in component instantly in React?

I'm building this website with MERN stack and having this rendering bug:
On start, I have a foodList table rendering out all of the food in the database.
I already have a useEffect() with the foodList inside the dependency array - so anytime the users make changes to the foodList table (Add/Edit/Delete), it will instantly render out that added dish without refreshing the page.
When users search for something in this Search & Filter bar, it will hide the foodList table and return a table of searchedFood that is filtered from the foodList array.
But when the users use this Search & Filter functionality and then try to Edit/Delete from that searchedFood table. It won't render the changes instantly - they have to refresh the page to see the changes they made.
This might relate to the useEffect() but I don't know how to apply it for the searchedFood table without disrupting the foodList table.
App.js
export default function App() {
const [foodName, setFoodName] = useState('')
const [isVegetarian, setIsVegetarian] = useState('no')
const [priceRange, setPriceRange] = useState('$')
const [foodUrl, setFoodUrl] = useState('')
const [foodList, setFoodList] = useState([])
const [searchedFood, setSearchedFood] = useState([])
const [noResult, setNoResult] = useState(false)
// Display food list:
useEffect(() => {
let unmounted = false
Axios.get("https://project.herokuapp.com/read")
.then((response) => {
if (!unmounted) {
setFoodList(response.data)
}
})
.catch(error => {
console.log(`The error is: ${error}`)
return
})
return () => {
unmounted = true
}
}, [foodList])
// Add Food to list:
const addToList = async (event) => {//Axios.post logic in here}
// Paginate states:
const [currentPage, setCurrentPage] = useState(1)
const [foodPerPage] = useState(5)
// Get current food:
const indexOfLastFood = currentPage * foodPerPage
const indexOfFirstFood = indexOfLastFood - foodPerPage
const currentFood = foodList.slice(indexOfFirstFood, indexOfLastFood)
const currentSearchedFood = searchedFood.slice(indexOfFirstFood, indexOfLastFood)
const paginate = (pageNumber) => {
setCurrentPage(pageNumber)
}
return (
<section>
<FilterSearch
foodList={foodList}
searchedFood={searchedFood}
setSearchedFood={setSearchedFood}
noResult={noResult}
setNoResult={setNoResult}
paginate={paginate}
/>
{noResult ? <ResultNotFound/>
:
<FoodListTable
foodName={foodName}
priceRange={priceRange}
isVegetarian={isVegetarian}
foodUrl={foodUrl}
foodList={foodList}
currentFood={currentFood}
searchedFood={searchedFood}
currentSearchedFood={currentSearchedFood}
totalFood={foodList.length}
totalSearchedFood={searchedFood.length}
currentPage={currentPage}
paginate={paginate}
noResult={noResult}
foodPerPage={foodPerPage}
/>
}
</section>
)
}
FoodListTable.js
export default function FoodListTable(props) {
return (
<div>
<table>
<thead>
<tr>
<th>
Food name
</th>
<th>Price</th>
<th>
Action
</th>
</tr>
</thead>
<body>
// Return a table with data from searchFood on search:
{props.searchedFood.length > 0 ? props.currentSearchedFood.map((val) => {
return (
<FoodListRow
val={val}
key={val._id}
foodName={val.foodName}
isVegetarian={val.isVegetarian}
priceRange={val.priceRange}
foodUrl={val.foodUrl}
/>
)
}) : props.currentFood.map((val) => { // If not on search, return a table with data from foodList:
return (
<FoodListRow
val={val}
key={val._id}
foodName={val.foodName}
isVegetarian={val.isVegetarian}
priceRange={val.priceRange}
foodUrl={val.foodUrl}
/>
)
})
}
</tbody>
</table>
// Display different Pagination on searched table and food list table:
{props.searchedFood.length > 0 ?
<Pagination foodPerPage={props.foodPerPage} totalFood={props.totalSearchedFood} paginate={props.paginate} currentPage={props.currentPage} />
:<Pagination foodPerPage={props.foodPerPage} totalFood={props.totalFood} paginate={props.paginate} currentPage={props.currentPage} />
}
</div>
)
}
FoodListRow.js
export default function FoodListRow(props) {
// Edit food name:
const [editBtn, setEditBtn] = useState(false)
const handleEdit = () => {
setEditBtn(!editBtn)
}
// Update Food Name:
const [newFoodName, setNewFoodName] = useState('')
const updateFoodName = (id) => {
if (newFoodName) {
Axios.put("https://project.herokuapp.com/update", {
id: id,
newFoodName: newFoodName,
})
.catch(error => console.log(`The error is: ${error}`))
}
}
// Delete food:
const deleteFood = (id) => {
const confirm = window.confirm(`This action cannot be undone.\nAre you sure you want to delete this dish?`);
if(confirm === true){
Axios.delete(`https://project.herokuapp.com/delete/${id}`)
}
}
return (
<tr key={props.val._id}>
<td>
{props.val.foodName}
{editBtn &&
<div>
<input
type="text"
name="edit"
placeholder="New food name.."
autoComplete="off"
onChange={(event) => {setNewFoodName(event.target.value)}}
/>
<button
onClick={() => updateFoodName(props.val._id)}
>
✓
</button>
</div>
}
</td>
<td>{props.val.priceRange}</td>
<td>
<a
href={props.val.foodUrl}
target="_blank"
rel="noopener noreferrer"
>
🔗
</a>
<button
onClick={handleEdit}
>
✏️
</button>
<button
onClick={() => deleteFood(props.val._id)}
>
❌
</button>
</td>
</tr>
);
}
As Mohd Yashim Wong mentioned, we need to re-render every time there's change to the backend.
I ditched the foodList inside the useEffect()'s dependency array and try another method because this is not the correct way to re-render the axios calls. It just keeps sending read requests indefinitely if I use this way. That might be costly.
This is what I have switched to:
I set the dependency array empty
Pull the data from the backend and return it to the frontend after the axios calls
addToList function:
const addToList = async (event) => {
event.preventDefault()
try {
await Axios.post(
"https://project.herokuapp.com/insert",
{
foodName: foodName,
isVegetarian: isVegetarian,
priceRange: priceRange,
foodUrl: foodUrl,
}
)
.then((response) => {
// Return the data to the UI:
setFoodList([...foodList, { _id: response.data._id, foodName: foodName, isVegetarian: isVegetarian, priceRange: priceRange, foodUrl: foodUrl }])
setFoodName('')
setIsVegetarian('no')
setPriceRange('$')
setFoodUrl('')
})
} catch(err) {
console.error(`There was an error while trying to insert - ${err}`)
}
}
updateFoodName function:
const updateFoodName = (id) => {
if (newFoodName) {
Axios.put("https://project.herokuapp.com/update", {
id: id,
newFoodName: newFoodName,
})
.then(() => {
// Update on searchedFood:
props.searchedFood.length > 0 ?
props.setSearchedFood(props.searchedFood.map((val) => {
return (
val._id === id ?
{
_id: id,
foodName: newFoodName,
isVegetarian: props.isVegetarian, priceRange: props.priceRange,
foodUrl: props.foodUrl,
} : val
)
})) //Update on foodList
: props.setFoodList(props.foodList.map((val) => {
return (
val._id === id ?
{
_id: id,
foodName: newFoodName,
isVegetarian: props.isVegetarian, priceRange: props.priceRange,
foodUrl: props.foodUrl,
} : val
)
}))
})
.catch(error => console.log(`Update name failed: ${error}`))
}
}
deleteFood function:
const deleteFood = (id) => {
const confirm = window.confirm(`This action cannot be undone.\nAre you sure you want to delete this dish?`);
if(confirm === true){
Axios.delete(`https://project.herokuapp.com/delete/${id}`)
.then(() => {
props.searchedFood.length > 0
? props.setSearchedFood(props.searchedFood.filter((val) => {
return val._id !== id
}))
: props.setFoodList(props.foodList.filter((val) => {
return val._id !== id
}))
})
}
}
You are never updating the text of the food name. Inside FoodListRow, you should create a state for the name of the food. Set this equal to props.val.foodName and then update it at the end of updateFoodName() after the axios request.

ReactJs, Data only loads when I clicked on the accordion header

This is my App.js
console.log(customer) shows the data on the console here, so I think there is no problem on my API.
let client = null;
let customer_id = null;
var customer = null;
const getCustomerId = () => {
client.get('ticket.requester.id').then(
function(data) {
customer_id = data['ticket.requester.id'].toString();
}
);
var settings = {
url:'/api/sunshine/objects/records?type=Customer',
type:'GET',
dataType: 'json',
};
client.request(settings).then(
function(data) {
var jsonCount = Object.keys(data.data).length;
var x = 0;
console.log(customer_id);
while(x < jsonCount) {
var cust = data.data[x];
if (cust.attributes.CustomerID == customer_id) {
customer = data.data[x];
// console.log(customer);
}
x = x + 1;
}
console.log(customer);
},
function(response) {
console.error(response.responseText);
}
);
}
const App = () => {
const [expandedSections, setExpandedSections] = useState([]);
const [expandedSections2, setExpandedSections2] = useState([]);
useEffect(() => {
client = window.ZAFClient.init();
getCustomerId();
}, []);
return (
<Row justifyContent="center">
<Col className="outer_column">
<Accordion className="first_accordion"
level={2}
expandedSections={expandedSections}
onChange={index => {
if (expandedSections.includes(index)) {
setExpandedSections(expandedSections.filter(n => n !== index));
} else {
setExpandedSections([index]);
}
}}
>
<Accordion.Section>
<Accordion.Header>
<Accordion.Label>Customer Management</Accordion.Label>
</Accordion.Header>
<Accordion.Panel>
<Row justifyContent="center">
<Col className="inner_column">
<Accordion
isCompact
level={5}
isExpandable
className="second_accordion"
>
<Accordion.Section>
<Accordion.Header>
<Accordion.Label>Customer Information</Accordion.Label>
</Accordion.Header>
<Accordion.Panel className="accordion_panel">
<Display jsonData = {JsonData} tryData = {customer}/>
</Accordion.Panel>
</Accordion.Section>
</Accordion>
</Col>
</Row>
</Accordion.Panel>
</Accordion.Section>
</Accordion>
</Col>
</Row>
)
}
export default App;
This is my Display.js:
function withMyHook(Component) {
return function WrappedComponent(props) {
const myHookValue = useZafClient();
return <Component {...props} myHookValue={myHookValue} />;
}
}
class Display extends React.Component {
constructor(props) {
super(props);
this.state = {
fields: this.props.jsonData.data[0].attributes,
errors: {},
customers: [],
flag: (this.props.jsonData.data[0].attributes.CustomerID === "") ? 'register' : 'view'
};
}
handleChange(field, e) {
let fields = this.state.fields;
fields[field] = e.target.value;
this.setState({ fields });
}
render() {
console.log("trydata");
console.log(this.props.tryData);
return(
<div>
{Object.keys(this.props.jsonData.data[0].attributes).map((key, i) => (
<p key={i}>
<span>{key}
<input value={this.state.fields[key] || ''}
placeholder={key}
disabled = {(this.state.flag === 'view') ? "disabled" : "" }
onChange={this.handleChange.bind(this,key)} /></span>
</p>
))}
{(this.state.flag === "register") ?
<Button onClick={() => this.setState({flag: 'view'})}> Register </Button> :
null
}
{(this.state.flag === "view") ?
<Button onClick={() => this.setState({flag: 'update'})}> Edit </Button> :
null
}
{(this.state.flag === "update") ?
<Button onClick={() => this.setState({flag: 'view'})}> Submit </Button> :
null
}
</div>
)
}
};
export default withMyHook(Display);
As you can see.. the API call on my App.js is being passed through tryData = {customer}, my problem is the data won't be pass to Display.js, not until I open the Accordion Customer Information.. you can see on the display.js that I am using this.props.jsonData.data[0].attributes instead of this.props.tryData.attributes, because I get type error Props error
Try to put variables inside of the App component that you pass as a props value
const App =()=>
{
let client=null,
....
}

not able to update state in reactsJs

i am using table input field to update state under map function to render it according to number of elements in the state.But when I used value={item.account} values are not updated in the state.which works fine when I use **value={accountCounter.account} where accountCounter is reactjs hook of type
const[accountCounter,setAccountCounter]=useState([
{ id: 1, account:"" ,accountOwner:""},
{ id: 2, account: "hi",accountOwner:"" },
{ id: 3, account: "bu" ,accountOwner:""}
And here is my rendering function
accountCounter.map((item,key)=>{
return(
<tr key={key}>
<td><input type="text" value={item.account}
name="account" onChange={(e)=>handleAccountCounter(e,item)}/></td>
<td><input type="text" value={item.accountOwner}
name="accountName" onChange={(e)=>handleAccountCounter(e,item)}/></td>
<td><span onClick={()=>deleteAccount(item.id)}>X</span></td>
</tr>
)
})}
here is my handleAccountCounter
const handleAccountCounter=(event,counter)=>{
const index = accountCounter.indexOf(counter);
accountCounter[index][event.target.name]=event.target.value;
setAccountCounter(accountCounter)
}
But the state is not getting modified when in input field value={item.account}.dont know why..will you help me out
Use the previous state values to create a new array:
const App = () => {
const [accountCounter, setAccountCounter] = useState([
{ id: 1, account: "", accountOwner: "" },
{ id: 2, account: "hi", accountOwner: "" },
{ id: 3, account: "bu", accountOwner: "" }
]);
const handleAccountCounter = (event, counter) => {
setAccountCounter((prevAccountCounter) => {
const newCounter = [...prevAccountCounter];
newCounter[prevAccountCounter.indexOf(counter)][event.target.name] =
event.target.value;
return newCounter;
});
};
const deleteAccount = (id) => {
setAccountCounter((prevAccountCount) =>
prevAccountCount.filter((item) => item.id !== id)
);
};
return accountCounter.map((item, index) => (
<tr key={index}>
<td>
<input
type="text"
value={item.account}
name="account"
onChange={(e) => handleAccountCounter(e, item)}
/>
</td>
<td>
<input
type="text"
value={item.accountOwner}
name="accountOwner"
onChange={(e) => handleAccountCounter(e, item)}
/>
</td>
<td>
<span onClick={() => deleteAccount(item.id)}>X</span>
</td>
</tr>
));
};
Instead of this
const handleAccountCounter = (event,counter) => {
const index = accountCounter.indexOf(counter);
accountCounter[index][event.target.name]=event.target.value;
setAccountCounter(accountCounter)
}
Do like this
const handleAccountCounter = (event, counter) => {
let temp = [...accountCounter] // Make a copy of state and then perform operations
const index = temp.indexOf(counter);
temp[index][event.target.name] = event.target.value;
setAccountCounter(temp)
}
Using Kartikey's answer, but you should use a callback because state updates are asynchronous:
const handleAccountCounter = (event, counter) => {
setAccountCounter((prev) => {
let newCounter = [...prev];
newCounter[prev.indexOf(counter)][event.target.name] = event.target.value;
return newCounter;
});
};
This ensures that the state updates in the correct order. See here for more info:
https://dmitripavlutin.com/how-react-updates-state/

Content Editable stays the same after changing page

I'm doing a web app that fetchs some info from the service and displays it in a table. I'm also using pagination. The objective is to receive some data and let the user change it, some of the fields don't have info yet, and the user can add it. The problem is, in this last situation, if the field is null and the user puts some info, after changing page with pagination from react, if in the place of the changed cell its another empty field, the info will stay, although its a different object.
export default function Product() {
const [resources, setResourcesData] = useState<PaginatedList>();
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage, setItemsPerPage] = useState(5);
const [sortValue, setSortValue] = useState("ASC");
const [sortPropertyName, setSortPropertyName] = useState("key");
const [searchString, setSearchString] = useState("");
const [searchPropertyName, setSearchPropertyName] = useState("Key");
/*just some info i needed to get the project name*/
const location = useLocation();
const str = JSON.stringify(location.state).split('"');
const prod = str[3];
const fetchItem = async () => {
let resourcesData: PaginatedList;
const fetchProducts = await axios.get(${config.SERVER_URL}/Resources, {
params: {
project: prod,
pageIndex: currentPage,
pageCount: itemsPerPage,
sortPropertyName: sortPropertyName,
sortOrder: sortValue,
searchPropertyName: searchPropertyName,
searchString: searchString,
},
});
resources?.items.forEach(res => {
let td = document.getElementById(res.key + res.culture + "comment");
var div = td?.childNodes.item;
console.log(div);
});
resourcesData = fetchProducts.data;
setResourcesData(resourcesData);
};
const editString = async (resx: IResource) => {
let resource: IResource;
let value = document.getElementById(resx.key + "value")?.innerText;
let comment = document.getElementById(resx.key + "comment")?.innerText;
if (comment === undefined) {
comment = "";
}
if (value === undefined) {
value = "";
}
console.log(value);
resource = {
project: prod,
key: resx.key,
value: value,
comment: comment,
culture: resx.culture,
};
await axios.put(${config.SERVER_URL}/Update, resource);
};
const nextList = () => {
setCurrentPage(currentPage + 1);
};
const previousList = () => {
setCurrentPage(currentPage - 1);
};
const onChangePrev = () => {
if (currentPage == 1) {
return true;
}
return false;
};
const onChangeNext = () => {
if (currentPage == resources?.totalPages) {
checkUndefined();
return true;
}
return false;
};
const firstList = () => {
setCurrentPage(1);
};
const lastList = () => {
setCurrentPage(resources!.totalPages);
};
const handleSortValueChange = (
e: React.MouseEvent<HTMLImageElement, MouseEvent>
) => {
if (e.currentTarget.classList.contains("asc")) {
e.currentTarget.classList.remove("asc");
e.currentTarget.classList.add("desc");
setSortValue("DESC");
} else {
e.currentTarget.classList.remove("desc");
e.currentTarget.classList.add("asc");
setSortValue("ASC");
}
};
function checkUndefined() {
}
useEffect(() => {
fetchItem();
}, [
currentPage,
itemsPerPage,
sortValue,
searchString,
searchPropertyName,
sortPropertyName,
]);
/*
const indexOfLastItem = currentPage * itemsPerPage;
const indexOfFirstItem = indexOfLastItem - indexOfLastItem;
*/
if (!resources?.items) {
return <div>Loading... </div>;
} else {
return (
<div className="App">
<div style={{ height: "5rem" }}></div>
<div className="styled-table">
<div className="div-grande">
<input
placeholder="Search"
type="text"
name="search"
id="search"
onChange={(s) => setSearchString(s.target.value)}
/>
<div className="radio-button">
Key
<label>
<input
type="radio"
value="key"
id="searchByKey"
checked={"key" === searchPropertyName}
onClick={(n) => setSearchPropertyName("key")}
/>
</label>
Value
<label>
<input
type="radio"
value="value"
name="searchByValue"
checked={"value" === searchPropertyName}
onClick={(n) => setSearchPropertyName("value")}
/>
</label>
</div>
<div className="div-arrow">
<img
data-testid="sortValue"
id="sortImage"
className="asc"
src="/arrow.svg"
alt="sort"
title={
sortValue
? "Press to ascending order"
: "Press to descending order"
}
onClick={handleSortValueChange}
/>
Order by:
<Select
className="select-order"
isSearchable={false}
closeMenuOnSelect={true}
id="order"
options={[
{ label: "Key", value: "Key" },
{ label: "Value", value: "Value" },
{ label: "Culture", value: "Culture" },
]}
defaultValue={{ label: "Key", value: "Key" }}
getOptionLabel={(option) => `${option.label}`}
getOptionValue={(option) => `${option.value}`}
onChange={(n) => setSortPropertyName(n!.value)}
/>
</div>
</div>
<Table id="table">
<thead>
<th>Key</th>
<th>Value</th>
<th>Comment</th>
<th>Language</th>
<th></th>
</thead>
<tbody>
{resources.items.map((resx) => (
<tr>
<td id={resx.key}>{resx.key}</td>
<td id={resx.key + resx.culture + "value"}>
<div id="value" contentEditable>
{resx.value}
</div>
</td>
<td id={resx.key + resx.culture + "comment"}>
<div id="comment" contentEditable>
{resx.comment}
</div>
</td>
<td id={resx.key + resx.culture}>{resx.culture}</td>
<td>
<Button
className="myButton"
onClick={() => editString(resx)}
>
Save
</Button>
</td>
</tr>
))}
</tbody>
</Table>
<Select
className="select"
isSearchable={false}
closeMenuOnSelect={true}
id="count"
options={[
{ label: 5, value: 5 },
{ label: 10, value: 10 },
{ label: 20, value: 20 },
{ label: 50, value: 50 },
{ label: 100, value: 100 },
]}
defaultValue={{ label: 5, value: 5 }}
getOptionLabel={(option) => `${option.label}`}
getOptionValue={(option) => `${option.value}`}
onChange={(n) => setItemsPerPage(n!.value)}
/>
<div>
<Pagination>
<Pagination.First onClick={() => firstList()} />
<Pagination.Prev
onClick={() => previousList()}
id="prev"
disabled={onChangePrev()}
/>
<Pagination.Next
onClick={() => nextList()}
id="next"
disabled={onChangeNext()}
/>
<Pagination.Last onClick={() => lastList()} />
</Pagination>
</div>
</div>
</div>
);
}
}
The checkUndefined function was an attempt to clear the row.
Here are some pictures to show better my problem.
I added the "we" in the second row
And after clicking the button to see the next page of the table the "we" is still there, in that place would be a empty fields.

Categories

Resources