How to turn this JSX table into input fileds? - javascript

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>

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

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

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!

Get key from datalist in Form.Control

I get from the API a json, with a list of each staff member:
const MOCK_STAFF = [{
id: 1,
name: "Jhon Doe",
department: "HR"
}, {
id: 2,
name: "Jane Doe",
department: "Research"
}, etc
Then they get mapped in a datalist <option>, inside a Form.Control component:
<Form.Group className="mb-3">
<Form.Label>Name</Form.Label>
<Form.Control
name='staffName'
value={0}
list="namesList"
onChange={(e) => onChangeHandler(e)}/>
<Form.Label>Department</Form.Label>
<Form.Control disabled
name=department
value={}
/>
<datalist id="namesList">
{MOCK_DATA.map( (data) => (
<option key={data.id} value={data.department}>{data.name}</option>
))}
</datalist>
</Form.Group>
sandbox link: https://codesandbox.io/s/modal-t59e7z?file=/src/App.tsx
I would like the onChange={(e) => onChangeHandler(e)} to get the data-value of <option key={data.id} on form submit, and to make the department Form.Control to reference the value of <option value={data.department} in the datalist. The 'key' id must not show to the user, it is used as a primary key on the database.
I have tried:
function onChangeHandler(e:React.SyntheticEvent) {
console.log(e.target.key);
}
but "property key does not exist on event.target". Nor I can use document.getElementById(); with react. How can I get the values 'key', 'value' and/or 'default-value` from a Form.Control with a datalist?
Thank you
I could not achieve this with data-list, but did so with react-select:
type StaffOption = {
label: string, value: number
}
const MOCK_DATA= [{
id: 1,
name: "Jhon Doe",
department: "HR"
}, {
id: 2,
name: "Jane Doe",
department: "Research"
}, {
id: 3,
name: "Elizabeth meyer",
department: "Operations"
}]
type NameOption = {value: number, label: string, department: string}
type NameOptions = Array<NameOption>
function AddNewRowModal(props:AddNewRowProps) {
const [selectedStaffID, setSelectedStaffID] = useState(0);
function onChangeHandler(option: OnChangeValue<StaffOption, false>,
actionMeta: ActionMeta<StaffOption>) {
console.log(option); //this returns all 3 values defined on type StaffOption
if (option?.value !== undefined) {
setSelectedStaffID(option.value!);
}
}
function BuildOptions (data:any[]) {
var options:NameOptions = []
data.forEach(element => {
options.push({
value: element.id!,
label: (element.name),
department: element.department});
});
return options;
var nameOptions = BuildOptions(MOCK_DATA);
return (
<Modal
show={props.showModal}
backdrop="static"
keyboard={false}
onHide={() => props.closeModal()} >
<Modal.Header closeButton>
<Modal.Title>Add new Entry</Modal.Title>
</Modal.Header>
<Modal.Body>
<Select
options={nameOptions}
onChange={onChangeHandler} />
</Modal.Body>
<ModalFooter>
<Button variant='primary'>Create Entry</Button>
<Button variant='danger' onClick={() => props.closeModal()}>Cancel</Button>
</ModalFooter>
</Modal>
);
}
And the codesandbox

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

React JS. How can I display the image inside the object?

How can I display the image inside the object in React.js?
const Area = () =>{
const flags = [
{ id: 1, name: "USA", image: "./us.png" },
{ id: 2, name: "Canada", image: "./ca.png" },
];
return (
<div>
{flags.map((area) => {
return <img key={area.id} src={area.image} />;
})}
</div>
)}
The very first thing that you need to do is wrap the src in {} which you're doing already.
Then if you're using webpack. Instead of : <img src={"./us.png"} />
You need to use require() like this <img src={require('./us.png')} />
const Area = () => {
const flags = [
{ id: 1, name: "USA", image: "./us.png" },
{ id: 2, name: "Canada", image: "./ca.png" },
]
return (
<div>
{flags.map((area) => {
return <img key={area.id} src={require(area.image)} />;
})}
</div>
)}
}
Another option would be to first import the image as shown below
import ca from './us.png' or const us = require('./us.png).
Then add them to your flags object like shown below:
import usa from './us.png;
import canada from './ca.png;
const Area = () => {
const flags = [
{ id: 1, name: "USA", image: usa },
{ id: 2, name: "Canada", image: canada },
]
return (
<div>
{flags.map((area) => {
return <img key={area.id} src={area.image} />;
})}
</div>
)}
}
You can use require for images inside an object.But your code works fine even without that you just have to return it inside return method().
const Area = () =>{
const flags = [
{ id: 1, name: "USA", image: require('./us.png') },
{ id: 2, name: "Canada", image: require('./ca.png') },
]
return (
<div>
{flags.map((area) =>
<img key={area.id} src={area.image} />
)}
</div>
)
}
return(
Area()
)
It works fine this way as well
const Area = () =>{
const flags = [
{ id: 1, name: "USA", image: "./us.png" },
{ id: 2, name: "Canada", image: "./ca.png" },
]
return (
<div>
{flags.map((area) =>
<img key={area.id} src={area.image} />
)}
</div>
)
}
return(
Area()
)
As I mentioned in my comments that please double check the path of the image. Image path might be a problem else it is looking fine. Moreover, you can press ctrl+click on path to route to that folder or check it manually.

Categories

Resources