Adding inputs on click in React.js project(with Redux toolkit) - javascript

I'm doing my PET project with Redux toolkit, but have some troubles with inputs. When i add an input on click it adds correctly, but i'm not sure it adds in right place(it's should be added in ITEMS array). Other issue is with it's data. If i add 2 inputs: 1) Item Name: 'Iphone 13', Unit Costs: '1200', unit: '2'; 2) Item Name: 'Iphone 12', Unit Costs: '1100', unit: '1'. It gonna add only last one and array length would be only 1.
Why is it hapenning? What i did wrong?
I've already tried using spread operator, but it shows error when i click on Add Item button.
Now the code.
InvoicesList.js file with INVOICES_LIST array which includes ITEMS where should be all items from inputs.
export const INVOICES_LIST = [
{
id: Math.random().toString(),
number: Math.random().toFixed(2),
invoice_num: "#1232",
bill_from: "Pineapple Inc.",
bill_to: "REDQ Inc.",
total_cost: "14630",
status: "Pending",
order_date: "February 17th 2018",
bill_from_email: "pineapple#company.com",
bill_from_address: "86781 547th Ave, Osmond, NE, 68765",
bill_from_phone: "+(402) 748-3970",
bill_from_fax: "",
bill_to_email: "redq#company.com",
bill_to_address: "405 Mulberry Rd, Mc Grady, NC, 28649",
bill_to_phone: "+(740) 927-9284",
bill_to_fax: "+0(863) 228-7064",
ITEMS: [
{
item_name: "A box of happiness",
unit_costs: "200",
unit: "14",
price: "2800",
sub_total: "133300",
vat: "13300",
grand_total: "14630",
},
],
},
{
id: Math.random().toString(),
number: Math.random().toFixed(2),
invoice_num: "#1232",
bill_from: "AMD Inc.",
bill_to: "Intel Inc.",
total_cost: "14630",
status: "Delivered",
order_date: "February 17th 2018",
bill_from_email: "pineapple#company.com",
bill_from_address: "86781 547th Ave, Osmond, NE, 68765",
bill_from_phone: "+(402) 748-3970",
bill_from_fax: "",
bill_to_email: "redq#company.com",
bill_to_address: "405 Mulberry Rd, Mc Grady, NC, 28649",
bill_to_phone: "+(740) 927-9284",
bill_to_fax: "+0(863) 228-7064",
ITEMS: [
{
item_name: "Unicorn Tears",
unit_costs: "500",
unit: "14",
price: "1700",
sub_total: "133300",
vat: "13300",
grand_total: "14630",
},
],
},
{
id: Math.random().toString(),
number: Math.random().toFixed(2),
invoice_num: "#1232",
bill_from: "Apple Inc.",
bill_to: "Samsung",
total_cost: "14630",
status: "Shipped",
order_date: "February 17th 2018",
bill_from_email: "pineapple#company.com",
bill_from_address: "86781 547th Ave, Osmond, NE, 68765",
bill_from_phone: "+(402) 748-3970",
bill_from_fax: "",
bill_to_email: "redq#company.com",
bill_to_address: "405 Mulberry Rd, Mc Grady, NC, 28649",
bill_to_phone: "+(740) 927-9284",
bill_to_fax: "+0(863) 228-7064",
ITEMS: [
{
item_name: "Rainbow Machine",
unit_costs: "700",
unit: "5",
price: "3500",
sub_total: "133300",
vat: "13300",
grand_total: "14630",
},
],
},
];
AddInvoiceItem.js file where you can find inputs and adding logic.
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { uiActions } from "../../store/ui-slice";
import classes from "./AddInvoiceItem.module.css";
import { useFormik } from "formik";
import Wrapper from "../../UI/Wrapper";
import Card from "../../UI/Card";
import Footer from "../../UI/Footer";
import Button from "../../UI/Button";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faCalendar } from "#fortawesome/free-solid-svg-icons";
import { faEllipsis } from "#fortawesome/free-solid-svg-icons";
import { invoiceActions } from "../../store/invoice-slice";
import { Link } from "react-router-dom";
const AddInvoiceItem = (props) => {
const date = new Date();
const options = ["Pending", "Shipped", "Delivered"];
const inputs = [{ itemName: "", unitCosts: "", unit: "" }];
const [startDate, setStartDate] = useState(date);
const [selectedOption, setSelectedOption] = useState(options[0]);
const [listItems, setListItems] = useState(inputs);
const optionClickHandler = (value) => () => {
setSelectedOption(value);
dispatch(uiActions.toggleMoreOptions());
};
const addInvoiceHandler = (invoice) => {
console.log(invoice);
console.log(selectedOption);
dispatch(
invoiceActions.addNewInvoice({
id: Math.random(),
invoiceNumber: invoice.invoiceNumber,
billFrom: invoice.billFrom,
billFromAddress: invoice.billFromAddress,
billTo: invoice.billTo,
billToAddress: invoice.billToAddress,
status: selectedOption,
order_date: startDate.toJSON(),
ITEMS: [
{
id: Math.random(),
item_name: invoice.itemName,
unit_costs: invoice.unitCosts,
units: invoice.unit,
},
],
})
);
};
const formikInvoice = useFormik({
initialValues: {
invoiceNumber: "",
billFrom: "",
billFromAddress: "",
billTo: "",
billToAddress: "",
status: selectedOption,
date: startDate.toJSON(),
ITEMS: [
{
id: Math.random(),
itemName: "",
unitCosts: "",
unit: "",
},
],
},
onSubmit: (val) => {
addInvoiceHandler(val);
},
});
const dispatch = useDispatch();
const toggleMoreOptions = () => {
dispatch(uiActions.toggleMoreOptions());
};
const showOtherOptions = useSelector(
(state) => state.ui.selectMoreOptionsIsVisible
);
let counter = 1;
const addItemHandler = () => {
setListItems(listItems.concat([{ itemName: "", unitCosts: "", unit: "" }]));
};
return (
<form onSubmit={formikInvoice.handleSubmit}>
<Wrapper isShrinked={props.isShrinked}>
<Card>
<div className={classes.content}>
<div className={classes["buttons-wrapper"]}>
<Link to="/invoices">
<button type="button" className={classes["cancel-btn"]}>
Cancel
</button>
</Link>
{/* <Link to="/invoices"> */}
<Button className={classes["save-btn"]}>Save</Button>
{/* </Link> */}
</div>
<div className={classes["invoice-info-wrapper"]}>
<div className={classes["invoice-info"]}>
<h3>Invoice Info</h3>
<input
placeholder="Number"
type="text"
name="invoiceNumber"
id="invoiceNumber"
onChange={formikInvoice.handleChange}
value={formikInvoice.values.invoiceNumber}
onBlur={formikInvoice.handleBlur}
></input>
</div>
<div className={classes["right-side-column"]}>
<div className={classes["order-status"]}>
<span>Order Status: </span>
<div className={classes.buttons}>
{showOtherOptions && (
<ul className={classes.options}>
{options.map((option) => (
<li
onClick={optionClickHandler(option)}
key={Math.random()}
>
{option}
</li>
))}
</ul>
)}
<button type="button" className={classes.status}>
{selectedOption}
</button>
<button
type="button"
className={classes.dots}
onClick={toggleMoreOptions}
>
<FontAwesomeIcon icon={faEllipsis} />
</button>
</div>
</div>
<div className={classes["order-date"]}>
<span>Order Date:</span>
<DatePicker
className={classes["order-date-input"]}
selected={startDate}
onChange={(val) => setStartDate(val)}
/>
<FontAwesomeIcon
icon={faCalendar}
className={classes.calendar}
></FontAwesomeIcon>
</div>
</div>
</div>
<div className={classes["order-bills"]}>
<div className={classes["bill-from"]}>
<input
placeholder="Bill From"
type="text"
name="billFrom"
id="billFrom"
onChange={formikInvoice.handleChange}
value={formikInvoice.values.billFrom}
onBlur={formikInvoice.handleBlur}
></input>
<textarea
placeholder="Bill From Address"
name="billFromAddress"
id="billFromAddress"
onChange={formikInvoice.handleChange}
value={formikInvoice.values.billFromAddress}
onBlur={formikInvoice.handleBlur}
></textarea>
</div>
<div className={classes["bill-to"]}>
<input
placeholder="Bill To"
type="text"
name="billTo"
id="billTo"
onChange={formikInvoice.handleChange}
value={formikInvoice.values.billTo}
onBlur={formikInvoice.handleBlur}
></input>
<textarea
placeholder="Bill To Address"
name="billToAddress"
id="billToAddress"
onChange={formikInvoice.handleChange}
value={formikInvoice.values.billToAddress}
onBlur={formikInvoice.handleBlur}
></textarea>
</div>
</div>
<div className={classes["table-wrapper"]}>
<table>
<colgroup>
<col className={classes.col1}></col>
<col className={classes.col2}></col>
<col className={classes.col3}></col>
<col className={classes.col4}></col>
<col className={classes.col5}></col>
<col className={classes.col6}></col>
</colgroup>
<thead>
<tr>
<td className={classes["more-padding"]}>#</td>
<td>Item Name</td>
<td>Unit Costs</td>
<td>Unit</td>
<td>Price</td>
<td></td>
</tr>
</thead>
<tbody>
{listItems.map((item, index) => (
<tr key={index}>
<td className={classes["more-padding"]}>{counter++}</td>
<td>
<input
placeholder="Item Name"
className={classes.inputs}
name="itemName"
id="itemName"
onChange={formikInvoice.handleChange}
value={formikInvoice.values.item_name}
onBlur={formikInvoice.handleBlur}
></input>
</td>
<td>
<input
placeholder="Unit Costs"
className={classes.inputs}
name="unitCosts"
id="unitCosts"
onChange={formikInvoice.handleChange}
value={formikInvoice.values.unit_costs}
onBlur={formikInvoice.handleBlur}
></input>
</td>
<td>
<input
placeholder="Unit"
className={classes.inputs}
name="unit"
id="unit"
onChange={formikInvoice.handleChange}
value={formikInvoice.values.units}
onBlur={formikInvoice.handleBlur}
></input>
</td>
<td>0</td>
<td></td>
{/* There should be dynamic values later */}
</tr>
))}
</tbody>
</table>
<div className={classes["add-item-btn"]}>
<button
onClick={addItemHandler}
type="button"
className={classes["add-item-btn"]}
>
Add Item
</button>
</div>
<div className={classes.total}>
<p className={classes["sub-total"]}>
<span>Sub Total: </span>
<span>$0</span>
{/* Dynamic value later here */}
</p>
<div className={classes["total-vat"]}>
<span>Total Vat:</span>
<div className={classes["total-sum"]}>
<span className={classes["input-wrapper"]}>
<input type="text" defaultValue="10"></input>
<span>%</span>
</span>
<span className={classes.sum}>$0</span>
{/* Dynamic value later here */}
</div>
</div>
<div className={classes["grand-total"]}>
<h3>Grand Total</h3>
<div className={classes.input}>
<input type="text" defaultValue="$"></input>
<span>0</span>
{/* Dynamic value later here */}
</div>
</div>
</div>
</div>
<div className={classes.dummy}></div>
</div>
</Card>
<Footer />
</Wrapper>
</form>
);
};
export default AddInvoiceItem;
invoice-slice.js file.
import { createSlice } from "#reduxjs/toolkit";
import { INVOICES_LIST } from "../Pages/Invoice/InvoicesList";
const invoiceSlice = createSlice({
name: "invoice",
initialState: {
invoices: INVOICES_LIST,
},
reducers: {
addNewInvoice(state, action) {
const newItem = action.payload;
state.invoices.push({
id: newItem.id,
billFrom: newItem.bill_from,
billFromAddress: newItem.billFromAddress,
billTo: newItem.bill_to,
billToAddress: newItem.bill_to_address,
invoiceNumber: newItem.invoice_num,
status: newItem.status,
order_date: newItem.order_date,
ITEMS: [
{
id: Math.random(),
item_name: newItem.item_name,
unit_costs: newItem.unit_costs,
units: newItem.units,
},
],
});
console.log(newItem);
},
removeInvoice(state, action) {
const id = action.payload;
state.invoices = state.invoices.filter((item) => item.id !== id);
},
editInvoice() {},
},
});
export const invoiceActions = invoiceSlice.actions;
export default invoiceSlice;
Also: should i give every item unique id? Because, i'm not sure if i need that.
P.S. here is github repo - https://github.com/stepan-slyvka/test-project
P.P.S. this is my PET project, so don't wonder why I'm using Context in one page and another Redux. It's only for learning purpose.

I've looked at your code now. This is one way to get it all to work, but, in general you should probably make a decision whether to use formik's state as the main state for listItems and refactor your code into that direction or do something else.
However, here is one ROUGH way to solve your problem, use it as a reference in making decisions on how to manage it.
Add the following to your AddinvoiceItem.js:
const updateItemHandler = (index, inputName, value) => {
listItems[index] = {...listItems[index], [inputName]: value};
}
const updateValuesOnSubmit = () => {
return listItems;
}
and change every input (itemName, unitCosts, unit) to use the new function in its onChange parameter:
onChange={(e) => updateItemHandler(index, 'THIS has to be the name of the input, for example itemName', e.currentTarget.value)}
Change addInvoiceHandler to use new function in its dispatch:
dispatch(
invoiceActions.addNewInvoice({
id: Math.random(),
invoiceNumber: invoice.invoiceNumber,
billFrom: invoice.billFrom,
billFromAddress: invoice.billFromAddress,
billTo: invoice.billTo,
billToAddress: invoice.billToAddress,
status: selectedOption,
order_date: startDate.toJSON(),
ITEMS: [
...updateValuesOnSubmit()
],
})
);
};
and finally, go to invoice-slice.js and do this:
ITEMS: [
...newItem.ITEMS
],
This is how you should be able to get multiple items within an invoice to your redux state. Let me emphasize once more that you should still consider using Formik's state and its management, handleChange features etc. as you've already chosen it for this task.
But this is still one way to do what you wanted to do. Hope it helps!

Related

how to get data from dynamically created input fields react

I'm trying to capture the inputs of dynamically created input fields and I'm only able to get the first set of exercise fields(Exercise, Reps, Sets)
import { useState } from "react";
export default StackTest;
function StackTest() {
const [formData, setFormData] = useState({
title: "",
date: "",
exercises: [{ Exercise: "benchpress", Reps: "5", Sets: "5" }],
});
const handle = (e, type, index) => {
setFormData({
title: formData.title,
date: formData.date,
exercises: [
{
Exercise: type === "E" ? e : formData.exercises[index].Exercise,
Reps: type === "R" ? e : formData.exercises[index].Reps,
Sets: type === "S" ? e : formData.exercises[index].Sets,
},
],
});
};
const updateForm = (e) => {
setFormData((currentFormData) => ({
...currentFormData,
[e.target.name]: e.target.value,
}));
};
const handleAddExercise = (e) => {
e.preventDefault();
setFormData((currentFormData) => {
return {
...currentFormData,
exercises: [
...currentFormData.exercises,
{ Exercise: "benchpress", Reps: "5", Sets: "5" },
],
};
});
};
return (
<>
<form action="">
<label htmlFor="">title</label>
<input
type="text"
name="title"
value={formData.title}
onChange={updateForm}
/>
<label htmlFor="">date</label>
<input
type="text"
name="date"
value={formData.date}
onChange={updateForm}
/>
{formData.exercises.map((exercise, index) => {
return (
<div key={index}>
<input
placeholder="exercise"
onChange={(e) => handle(e.target.value, "E", index)}
/>
<input
placeholder="reps"
onChange={(e) => handle(e.target.value, "R", index)}
/>
<input
placeholder="sets"
onChange={(e) => handle(e.target.value, "S", index)}
/>
<button onClick={handleAddExercise}>Add Exercise</button>
</div>
);
})}
</form>
</>
);
}
Whenever I type in one of the added exercise fields it will just remove it after the first character. I also tried to add an if statement in the handle function to check if the index was the same but as I'm new to react and coding in general I may have implemented that wrong.
The issue is that you're overwriting the contents of your exercises array when you need to create a copy of it and mutate it.
The simplest solution would be to create a copy of your Exercises array, make any mutations needed and then update your state.
import { useState } from "react";
export default StackTest;
function StackTest() {
const [formData, setFormData] = useState({
title: "",
date: "",
exercises: [{ Exercise: "benchpress", Reps: "5", Sets: "5" }],
});
const handle = (e, type, index) => {
let localExer = [ ...formData.exercises ];
localExer[index].Exercise = (type === "E" ? e : formData.exercises[index].Exercise)
localExer[index].Reps = (type === "R" ? e : formData.exercises[index].Reps)
localExer[index].Sets = (type === "S" ? e : formData.exercises[index].Sets)
setFormData({
title: formData.title,
date: formData.date,
exercises: [ ...localExer],
});
};
const updateForm = (e) => {
setFormData((currentFormData) => ({
...currentFormData,
[e.target.name]: e.target.value,
}));
};
const handleAddExercise = (e) => {
e.preventDefault();
setFormData((currentFormData) => {
return {
...currentFormData,
exercises: [
...currentFormData.exercises,
{ Exercise: "benchpress", Reps: "5", Sets: "5" },
],
};
});
};
return (
<>
<form action="">
<label htmlFor="">title</label>
<input
type="text"
name="title"
value={formData.title}
onChange={updateForm}
/>
<label htmlFor="">date</label>
<input
type="text"
name="date"
value={formData.date}
onChange={updateForm}
/>
{formData.exercises.map((exercise, index) => {
return (
<div key={index}>
<input
placeholder="exercise"
onChange={(e) => handle(e.target.value, "E", index)}
/>
<input
placeholder="reps"
onChange={(e) => handle(e.target.value, "R", index)}
/>
<input
placeholder="sets"
onChange={(e) => handle(e.target.value, "S", index)}
/>
<button onClick={handleAddExercise}>Add Exercise</button>
</div>
);
})}
</form>
</>
);
}

How to search objects react.js javascript?

Thanks for your time reading.
I need to sort countries by Language or Continent, the user selects the option he wants in the buttons.
countries is an array of objects of each country that contain:
languages is an array of objects, because each country can have more than one language
continent is an object with the continent name
Complete example(countries array content): https://github.com/gonzaloramosf/countries
If the user select for example continents and types in the input "es" all the results related whit content Asia listed together in a group and do not repeat the continent title in each one, same i need with languages.
This is my code:
const CountrySearch = ({countries}) => {
const [searchTerm, setSearchTerm] = useState("");
console.log(countries)
return (
<div className="search">
<h1>Country Search</h1>
<span> Some random text </span>
<div className="searchResults">
<input type="text" placeholder="Search country..." onChange={event => {
setSearchTerm(event.target.value)
}}/>
<div className="groupBy">
<h2> Group by: </h2>
<div>
<button> Continent </button>
<button> Language </button>
</div>
</div>
<div>
{countries.filter((val) => {
if (searchTerm === "") {
return ""
} else if (val.name.toLowerCase().includes(searchTerm.toLowerCase())){
return val
}
}).map((val, key) => {
return (
<div key={key}>
<h2> {val.continent.name} </h2>
<div className="countryInfo">
<div>
<span>{val.emoji}</span>
<h3> {val.name} </h3>
</div>
<p> Capital: {val.capital} </p>
<p> Currency: {val.currency} </p>
</div>
</div>
)
})
}
</div>
</div>
</div>
)
}
export default CountrySearch;
First filter the data and then group it by continent using reduce and then loop over the arrays and create the desired JSX.
You can refer the snippet below (type "s" in the input box):
const countries = [
{
name: "India",
continent: { name: "Asia" },
languages: [{ name: "Hindi" }, { name: "English" }, { name: "Marathi" }],
},
{
name: "Sri Lanka",
continent: { name: "Asia" },
languages: [{ name: "Srilankan" }, { name: "Tamil" }],
},
{
name: "Spain",
continent: { name: "Europe" },
languages: [{ name: "Spanish" }, { name: "English" }],
},
{
name: "Slovakia",
continent: { name: "Europe" },
languages: [{ name: "English" }],
},
];
function App() {
const [searchTerm, setSearchTerm] = React.useState("");
return (
<div>
<input
type="text"
value={searchTerm}
onChange={({ target }) => setSearchTerm(target.value)}
/>
{Object.entries(
countries
.filter((c) =>
c.name.toLowerCase().includes(searchTerm.toLowerCase())
)
.reduce((res, c) => {
if (!res[c.continent.name]) {
res[c.continent.name] = [];
}
res[c.continent.name].push(c);
return res;
}, {})
).map(([continent, countries]) => (
<ul key={continent}>
<li>
<div>{continent}</div>
<ul>
{countries.map(({ name, languages }) => (
<li key={name}>
<div>{name}</div>
<ul>
{languages.map(({ name }) => (
<li key={name}>{name}</li>
))}
</ul>
</li>
))}
</ul>
</li>
</ul>
))}
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
<script crossorigin src="https://unpkg.com/react#18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#18/umd/react-dom.development.js"></script>
<div id="root"></div>
Following is the portion of code from the above snippet that does the grouping:
Object.entries(
countries
.filter((c) => c.name.toLowerCase().includes(searchTerm.toLowerCase()))
.reduce((res, c) => {
if (!res[c.continent.name]) {
res[c.continent.name] = [];
}
res[c.continent.name].push(c);
return res;
}, {})
);

Loops inside react components leading to rendering of sub components

I have a data as below
myArr = [
{
"Sl.No": "n1",
company: "ABC",
Name: "Sam",
Designation: "Architect",
Salary: "100",
},
{
"Sl.No": "n2",
company: "ABC",
Name: "Bill",
Designation: "Engineer",
Salary: "200",
},
{
"Sl.No": "n3",
company: "ABC",
Name: "Jill",
Designation: "HR",
Salary: "300",
},
{
"Sl.No": "n4",
company: "XYZ",
Name: "Bill",
Designation: "Engineer",
Salary: "250",
},
{
"Sl.No": "n5",
company: "XYZ",
Name: "Tom",
Designation: "Mechanic",
Salary: "150",
},
{
"Sl.No": "n6",
company: "LMN",
Name: "Tom",
Designation: "Mechanic",
Salary: "150",
},
];
I want to create a react app which shows the data as below. Nothing but listing the employees & their designations under the name of the company.
The boxes on the right are number of doses of vaccine taken (data comes from somewhere else)
I have the components set-up like so
Inside App.js
I have left out importing the components , css & all that for simplcity
export const App = () => {
return (
<div className=app}>
<CompanyInfo />
</div>
);
}
Inside CompanyInfo.js
export const CompanyInfo= () => {
let companies= [...new Set(myArr.map((item) => item.company))];
const renderingComponents = (company: string, index: number) => {
return (
<Fragment key={index}>
<p className="company-name">{company}</p>
<div className="category-employees">
<CompanyEmployee toggled={toggled} />
</div>
;
</Fragment>
);
};
return (
<div className=company-info}>
{companies.map((item, index) => renderingComponents(item, index))}
</div>
);
}
So far, so good, I can render the titles of all the companies & I have hardcoded the CompanyEmployee to see if it populates within every company & it does. However, I want CompanyEmployee to be dynamic & I am not able to figure our how to pass the company related info to the components (that data will have info of all the company employees) and then map the CompanyEmployee component on that data.
Inside CompanyEmployee.js
Please note that this is like a wrapper for 2 components
export const CompanyEmployee= () => {
return (
<div className=ce}>
<EmployeePrimaryDetails />
<EmployeeVacDetails />
</div>
);
}
Inside EmployeePrimaryDetails.js
export const EmployeePrimaryDetails= (props) => {
return (
<div className=epd>
<span className="name">{props.Name}</span>
<span className="designation">{props.Designation}</span>
</div>
);
}
Can anyone guide me on how I render EmployeePrimaryDetails.js for each employee of the company?
I tried to do a for of, forEach, map in the renderingComponents function of CompanyInfo itself but when I try that I get the Typescript error "Expression Expected" (I am using typescript with React in my project).
Any help is appreciated.
Inside renderingComponents function you can say:
const filteredList = myArr.filter(employee => employee.company === company);
filteredList.map(employee => (<CompanyEmployee employee={employee} toggled={toggled} />));
Resulting in this:
const renderingComponents = (company: string, index: number) => {
const filteredList = myArr.filter(employee => employee.company === company);
return (
<Fragment key={index}>
<p className="company-name">{company}</p>
<div className="category-employees">
{filteredList.map(employee => (<CompanyEmployee employee={employee} toggled={toggled} />))}
</div>
;
</Fragment>
);
};
So in CompanyEmployee component you can destructure the data you need.

How to turn this JSX table into input fileds?

How would I convert this into a bunch of inputs instead of a table ?
I know the snippet is not runnable btw. If someoneone can just give me a starter or more guidance id appreciate it
like this:
function MyTable(props) {
console.log(props);
const initState = [
{ id: 1, name: "bread", quantitiy: 50, location: "cupboard" },
{ id: 2, name: "milk", quantitiy: 20, location: "fridge" },
{ id: 3, name: "water", quantitiy: 10, location: "fridge" },
{ id: 4, name: "rice", quantitiy: 10, location: "pantry" }
];
const [state, setState] = React.useState(initState);
return (
<table>
<tr key={"header"}>
{Object.keys(state[0]).map((key) => (
<th>{key}</th>
))}
</tr>
{state.map((item) => (
<tr key={item.id}>
{Object.values(item).map((val) => (
<td>{val}</td>
))}
</tr>
))}
</table>
);
}
ReactDOM.render(<MyTable staff={"hello"} />, document.getElementById("target"));
The val variable inside your state.map loop should be the value that you need, you can also use the reference to the item object above to give it a specific name for example.
Try replacing <td>{val}</td> with:
<td>
<input type="text" value={val} name={item.name}>
</td>
This should help as a starting point.
I found the answer, this is what happens when i code without coffee
<div>
<div>
{ Object.keys(state[0]).map((key) => (
<input type="text" value={key} id="name" name="productName" />
))}
</div>
{state.map((item) => (
<div key={item.id}>
{Object.values(item).map((val) => (
<input type="text" value={val} id="name" name="productName" />
))}
</div>
))}
</div>

Filling a model with a list from Textarea

Now I do not really understand you. Sorry, I just started this whole study not so long ago. I’ll try to explain again what I can’t do.
I have an empty object and an object with data with the same structure.
data: [
{id: 1, title: "title1"},
{id: 2, title: "title1"},
{id: 3, title: "title3"},
{id: 4, title: "title4"},
{id: 5, title: "title3"}
],
item: [
{
itemId: "",
itemname: ""
}
]
And I have select and textarear. Select have data, textarear empty. Textarear displays title.
I want to press a button. Selected item from select. copied to textarear (title only), and also itemId - this selected element id: 5 and itemname - the same title: "title3" element, was recorded in item [].
https://codesandbox.io/s/priceless-hermann-g9flw
Please do check now
import React from "react";
class App extends React.Component {
constructor() {
super();
this.state = {
id: null,
title: "",
filmItem: "",
listFilms: [],
data: [
{ id: 1, title: "title1" },
{ id: 2, title: "title2" },
{ id: 3, title: "title3" },
{ id: 4, title: "title4" }
],
item: []
};
this.onChange = this.onChange.bind(this);
this.onChangeArea = this.onChangeArea.bind(this);
this.addFilm = this.addFilm.bind(this);
this.choice = this.choice.bind(this);
}
addFilm(film) {
const selectedData = this.state.data.find(item => item.id == film);
console.log(selectedData);
this.setState({
listFilms: [...this.state.listFilms, selectedData.title],
item: [
...this.state.item,
{ itemId: selectedData.id, itemname: selectedData.title }
]
});
}
onChange = e => {
this.setState({ [e.target.name]: e.target.value });
};
onChangeArea = e => {
this.setState({ [e.target.name]: e.target.value.split("\n") });
};
choice(title) {
this.setState({ filmItem: title });
}
render() {
return (
<div className="App">
<div className="row App-main">
<div>
<select name="filmItem" size="4" onChange={e => this.onChange(e)}>
{this.state.data.map(film => (
<option key={film.title} value={film.id}>
{film.title}
</option>
))}
</select>
</div>
<div>
<button
className="editButton"
onClick={() => this.addFilm(this.state.filmItem)}
>
button
</button>
</div>
<div>
<textarea
name="films"
onChange={this.onChangeArea}
value={this.state.listFilms.map(r => r).join("\n")}
/>
</div>
<div>
<input type="text" name="text-input" onChange={this.onChange} />
</div>
</div>
<pre style={{ whiteSpace: "pre-wrap" }}>
{JSON.stringify(this.state)}
</pre>
</div>
);
}
}
export default App;

Categories

Resources