Content Editable stays the same after changing page - javascript

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.

Related

Add object inside of array react input value

I want add object inside of array items
I am trying to manage objects inside of an array with useState but is not working i have only in object but I want the object in interior of the array of items. When I click add items on the button i want add the element and if possible remove this element when i click remove items in button link with inputs (see the image)
Like :
company:"Apple",
companyAdress:"5 avenue triagle",
items: [
{
itemName: Computer,
itemQuantity: 20,
itemPrice: 209
},
{
itemName: Computer,
itemQuantity: 20,
itemPrice: 209
},
]
My code :
const [info, setInfo] = useState({});
const [itemForm, setItemForm] = useState({ num: 1 })
const handleRemoveItem = (e) => {
e.preventDefault();
setItemForm((itemForm) => ({ num: itemForm.num - 1 }))
}
const handleAddItem = (e) => {
e.preventDefault();
setItemForm((itemForm) => ({ num: itemForm.num + 1 }))
}
<label>Company</label>
<input onChange={(e) => { setInfo({ ...info, company: e.currentTarget.value}); }} placeholder="Company"></input>
<label>company Adress</label>
<input onChange={(e) => { setInfo({ ...info, companyAdress: e.currentTarget.value }); }} placeholder="Adresse"></input>
<ul className="space-y-3">
{[...Array(itemForm.num)].map((x, i) => {
return (
<li key={i}>
<div>
<input onChange={(e) => { setInfo({...info,itemName: e.currentTarget.value });}} name="itemName" placeholder="itemName:" ></input>
<input onChange={(e) => { setInfo({ ...info, itemQuantity: e.currentTarget.value }); }} type="number" name="itemQuantity" placeholder="Quantity:"></input>
<input onChange={(e) => { setInfo({ ...info, itemPrice: e.currentTarget.value }); }} type="number" name="itemPrice" placeholder="Price:"></input>
<button onClick={handleRemoveItem}>Enlever </button>
<button onClick={handleAddItem}>+ Add New Item</button>
</div>
</li>
)
}
)}
</ul>
i do something like this using an id to find the iteminfo.
i am currying the itemid here but you could put the itemId as part of the input id and find it that way if you like - then you could use one function. anyway hope it helps
also i am just using the id as the key for the object you might what to be more strict on this ¯_(ツ)_/¯
i would also put the factory and defaultInfo else where in your app
import { useState } from "react";
import { v4 as uuidv4 } from "uuid";
const defaultItemFactory = () => {
return { itemName: "", itemQuantity: "", itemPrice: "", id: uuidv4() };
};
const defaultInfo = {
company: "",
companyAdress: "",
items: [defaultItemFactory()],
};
function App() {
const [info, setInfo] = useState(defaultInfo);
const changeHanlder = (event) => {
const { id, value } = event.currentTarget;
setInfo((_info) => {
return { ..._info, [id]: value };
});
};
const itemHanlder = (itemId) => (event) => {
const { id, value } = event.currentTarget;
setInfo((_info) => {
if (id === "add")
return { ..._info, items: _info.items.concat(defaultItemFactory()) };
const items = _info.items
.map((item) => {
if (item.id !== itemId) return item;
if (id === "remove") return null;
return { ...item, [id]: value };
})
.filter((out) => out);
return { ..._info, items };
});
};
return (
<div className="App">
<label>Company</label>
<input
id={"company"}
value={info.company}
onChange={changeHanlder}
placeholder="Company"
></input>
<label>company Adress</label>
<input
id={"companyAdress"}
value={info.companyAdress}
onChange={changeHanlder}
placeholder="Adresse"
></input>
<ul className="space-y-3">
{info.items &&
info.items.map((item, i) => {
return (
<li key={`item-${item.id}`}>
<div>
<input
id={"itemName"}
value={item.itemName}
onChange={itemHanlder(item.id)}
name="itemName"
placeholder="itemName:"
></input>
<input
id={"itemQuantity"}
value={item.itemQuantity}
onChange={itemHanlder(item.id)}
type="number"
name="itemQuantity"
placeholder="Quantity:"
></input>
<input
id={"itemPrice"}
value={item.itemPrice}
onChange={itemHanlder(item.id)}
type="number"
name="itemPrice"
placeholder="Price:"
></input>
<button id={"remove"} onClick={itemHanlder(item.id)}>
Enlever{" "}
</button>
<button id={"add"} onClick={itemHanlder(item.id)}>
+ Add New Item
</button>
</div>
</li>
);
})}
</ul>
</div>
);
}
export default App;

how to delete a row in table in reactjs

I'm trying to implement a delete operation on table rows. but it keeps on throwing errors. So I need some help to figure this out.
I don't know to how to set id that can be auto incremented so I gave Date.now().
now what I want is to delete the row that i perform the delete operation on.
I'm new to react so sorry for the bad code. thank you in advance.
heres my code
import React from "react";
import { CirclesWithBar } from "react-loader-spinner";
import { useState } from "react";
import Table from "./Table";
function Main() {
// *****INITIALIZING*****
const [tableData, setTableData] = useState([])
const [formInputData, setformInputData] = useState(
{
id: Date.now(),
Name: '',
email: '',
}
);
const [loading, setloading] = useState(false);
// const deleteTableRows = (index)=>{
// const rows = [...rowsData];
// rows.splice(index, 1);
// setTableData(rows);
// }
// **********DECLARING FUNCTIONS*********
const handleChange = (evnt) => {
const newInput = (data) => ({ ...data, id: Date.now(), [evnt.target.name]: evnt.target.value })
setformInputData(newInput)
}
const handleSubmit = (evnt) => {
evnt.preventDefault();
setloading(true)
const checkEmptyInput = !Object.values(formInputData).every(res => res === "")
if (checkEmptyInput) {
const newData = (data) => ([...data, formInputData])
setTableData(newData);
const emptyInput = { id: '', Name: '', email: '' }
setformInputData(emptyInput)
}
setTimeout(() => {
setloading(false)
}, 1000)
}
const singleDelete = (event) => {
event.preventDefault();
setloading(true)
const handleDelete = (id) => {
const newArr = [...tableData];
console.log(tableData);
const index = setTableData.findIndex((data) => data.name(id) === id);
console.log(index);
newArr.splice(index, 1);
setTableData(newArr);
}
setTimeout(() => {
setloading(false)
}, 1000)
}
// ************RETURNING VALUES************
return (
<div className="container">
<div className="row">
<div className="col-sm-8">
<div className="col">
<input type="text" onChange={handleChange} value={formInputData.Name} name="Name" className="form-control" placeholder="Name" />
</div>
<div className="col">
<input type="email" onChange={handleChange} value={formInputData.email} name="email" className="form-control" placeholder="Email Address" />
</div>
<div className="col">
<input type="submit" onClick={handleSubmit} className="btn btn-success" />
{
loading ?
<CirclesWithBar
height="75"
width="100"
color="#002B5B"
wrapperStyle={{}}
wrapperClass=""
visible={true}
alignSelf='center'
outerCircleColor=""
innerCircleColor=""
barColor=""
ariaLabel='circles-with-bar-loading' loading={loading} size={50} />
:
<div>
{
<table className="table" id='table'>
<thead>
<tr>
<th>S.N</th>
<th>ID</th>
<th>Full Name</th>
<th>Email Address</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{
tableData.map((data, index) => {
return (
<tr>
<td>{index + 1}</td>
<td>{data.id}</td>
<td>{data.Name}</td>
<td>{data.email}</td>
<td><button value={data.id} onClick={() => singleDelete(data.id)} className="btn btn-danger">Delete</button></td>
</tr>
)
})
}
</tbody>
</table>
}
</div>
}
</div>
</div>
</div>
</div>
);
}
export default Main;
First, the error happens because you don't pass the click event parameter to the function.
It should be like that.
(e) => singleDelete(e, data.id)
Second, You can just use filter method to delete the item by add a condition any element that doesn't have this id.
const singleDelete = (event, id) => {
event.preventDefault();
setloading(true);
setTableData((prev) => prev.filter((i) => i.id !== id));
setTimeout(() => {
setloading(false);
}, 1000);
};
This is a full example of code.
import React from "react";
import { CirclesWithBar } from "react-loader-spinner";
import { useState } from "react";
function Main() {
// *****INITIALIZING*****
const [tableData, setTableData] = useState([]);
const [formInputData, setformInputData] = useState({
id: Date.now(),
Name: "",
email: ""
});
const [loading, setloading] = useState(false);
// const deleteTableRows = (index)=>{
// const rows = [...rowsData];
// rows.splice(index, 1);
// setTableData(rows);
// }
// **********DECLARING FUNCTIONS*********
const handleChange = (evnt) => {
const newInput = (data) => ({
...data,
id: Date.now(),
[evnt.target.name]: evnt.target.value
});
setformInputData(newInput);
};
const handleSubmit = (evnt) => {
evnt.preventDefault();
setloading(true);
const checkEmptyInput = !Object.values(formInputData).every(
(res) => res === ""
);
if (checkEmptyInput) {
const newData = (data) => [...data, formInputData];
setTableData(newData);
const emptyInput = { id: "", Name: "", email: "" };
setformInputData(emptyInput);
}
setTimeout(() => {
setloading(false);
}, 1000);
};
const singleDelete = (event, id) => {
event.preventDefault();
setloading(true);
setTableData((prev) => prev.filter((i) => i.id !== id));
setTimeout(() => {
setloading(false);
}, 1000);
};
// ************RETURNING VALUES************
return (
<div className="container">
<div className="row">
<div className="col-sm-8">
<div className="col">
<input
type="text"
onChange={handleChange}
value={formInputData.Name}
name="Name"
className="form-control"
placeholder="Name"
/>
</div>
<div className="col">
<input
type="email"
onChange={handleChange}
value={formInputData.email}
name="email"
className="form-control"
placeholder="Email Address"
/>
</div>
<div className="col">
<input
type="submit"
onClick={handleSubmit}
className="btn btn-success"
/>
{loading ? (
<CirclesWithBar
height="75"
width="100"
color="#002B5B"
wrapperStyle={{}}
wrapperClass=""
visible={true}
alignSelf="center"
outerCircleColor=""
innerCircleColor=""
barColor=""
ariaLabel="circles-with-bar-loading"
loading={loading}
size={50}
/>
) : (
<div>
{
<table className="table" id="table">
<thead>
<tr>
<th>S.N</th>
<th>ID</th>
<th>Full Name</th>
<th>Email Address</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{tableData.map((data, index) => {
return (
<tr>
<td>{index + 1}</td>
<td>{data.id}</td>
<td>{data.Name}</td>
<td>{data.email}</td>
<td>
<button
value={data.id}
onClick={(e) => singleDelete(e, data.id)}
className="btn btn-danger"
>
Delete
</button>
</td>
</tr>
);
})}
</tbody>
</table>
}
</div>
)}
</div>
</div>
</div>
</div>
);
}
export default Main;
This is working example with codesandbox.
Just modify your singleDelete function in this way -
const singleDelete = (id) => {
setloading(true);
const newTableData = tableData.filter(item => item.id !== id );
setTableData(newTableData)
setTimeout(() => {
setloading(false)
}, 1000)
}

How to chain two filters in react.js

I can't seem to filter two separate things in react.js
I am able to filter by 'hotel ratings using state' but when I tried to add another, it wouldn't work. In the console it says should have a unique key prop.
How can I filter both data sets? currently i'm filtering one data set with
.filter((h) => filter.ratings.includes(h.hotel.starRating))
when I tried creating something similar like this
(filter((room) => extra.occupancy.includes(room.occupancy.maxAdults))
it breaks the code, why is that ?
This is my code:
import { useEffect, useState } from "react";
import './App.css';
export default function App() {
const [hotelRooms, setHotelRooms] = useState([]);
const [filter, setFilter] = useState({ ratings: ["1", "2", "3", "4", "5"] });
const [extra, setExtra] = useState ({occupancy: ["1", "2", "3", "4", "5"] });
const fetchHotels = async () => {
const res = await fetch(
"https://obmng.dbm.guestline.net/api/hotels?collection-id=OBMNG"
);
const hotels = await res.json();
const hotelRooms = [];
for (const hotel of hotels) {
const res = await fetch(
`https://obmng.dbm.guestline.net/api/roomRates/OBMNG/${hotel.id}`
);
const info = await res.json();
hotelRooms.push({ hotel, rooms: info.rooms });
}
setHotelRooms(hotelRooms);
};
useEffect(() => {
fetchHotels();
}, []);
const handleRatingFilter = (e) => {
if (e.target.checked) {
// adding value
const temp = [...filter.ratings];
temp.push(e.target.value);
setFilter({ ...filter, ratings: temp });
} else {
// removing value
setFilter({
...filter,
ratings: [...filter.ratings.filter((v) => v !== e.target.value)]
});
}
};
const handleOccupancyExtra = (e) => {
if (e.target.checked) {
const perm = [...extra.occupancy];
perm.push(e.target.value);
setExtra({...extra, occupancy: perm});
} else {
setExtra ({
...extra,
occupancy: [...extra.occupancy.filter((d) => d !== e.target.value)]
});
}
}
return (
<div className="App">
<div>
{["1", "2", "3", "4", "5"].map((star) => (
<div key={"input-" + star}>
<input
id={"rated" + star}
value={star}
name="ratings"
type="checkbox"
checked={filter.ratings.includes(star)}
onChange={handleRatingFilter}
/>
<label htmlFor={"rated" + star}>Rated {star} star</label>
</div>
))}
</div>
<div>
{["1", "2", "3", "4", "5"].map((adults) => (
<div key={"adults" + adults}>
<input
id={"maximum" + adults}
value={adults}
name="extra"
type="checkbox"
checked={extra.occupancy.includes(adults)}
onChange={handleOccupancyExtra}
/>
<label htmlFor={"maximum" + adults}>adults {adults}</label>
</div>
))}
</div>
{hotelRooms
.filter((h) => filter.ratings.includes(h.hotel.starRating))
.map((h) => (
<div>
<h2> Name: {h.hotel.name}</h2>
<p> Description: {h.hotel.description}</p>
<p> Rating: {h.hotel.starRating}</p>
<p> Postcode: {h.hotel.postcode}</p>
<p> City: {h.hotel.town}</p>
<p style={{ fontWeight: "bold" }}>Rooms:</p>
{
h.rooms.map((room) => (
<div>
<h5>Occupancy</h5>
<div> adults: {room.occupancy.maxAdults}</div>
<div> Children: {room.occupancy.maxChildren}</div>
<div> Maximum guests: {room.occupancy.maxOverall}</div>
<div> Room type: {room.name}</div>
</div>
))}
</div>
))}
</div>
);
}
You can add multiple conditions inside filter.
Example:
const arr = [1,2,3,4,5,6,7,8,9,10]
const evenNums = arr.filter(num => num%2===0)
const biggerThan5 = arr.filter(num => num > 5)
const evenAndBiggerThan5 = arr.filter(num => num > 5 && num%2 === 0)
console.log("evenNums:", evenNums)
console.log("biggerThan5:", biggerThan5)
console.log("evenAndBiggerThan5:", evenAndBiggerThan5)
In your case
{hotelRooms
.filter((h) => filter.ratings.includes(h.hotel.starRating) && /* other condition (e.g. extra.occupancy.includes(...) */)
Codesandbox
This is a codesandbox based on my understanding of what you want to do.

how to fetch api data using react js

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

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/

Categories

Resources