Send the selected option to the backend - javascript

I have a select menu (with three options) along with a search bar. All I want is to save the selected option and the searched term and send them to the back-end. Here is my code:
import React, { useState, useEffect } from 'react'
const Table = () => {
const navigate = useNavigate()
const [users, setUsers] = useState([]);
const [currentUsers, setCurrentUsers] = useState([]);
const [search, setSearch] = useState('');
const [column, setColumn] = useState(''); //for saving the selected option
useEffect(async () => {
try {
const response = await getUsers(search);
setUsers(response.data.users);
} catch (error) { }
}, [search]);
return (
<input type='text' placeholder='search..' onChange={(e) => setSearch(e.target.value)} value={search} />
<select aria-label=".form-select-sm example">
<option selected value="1">all</option>
<option value="2">name</option>
<option value="3">phone</option>
</select>
<table className='w-full border-separate rounded-md'>
<thead>
<tr className='bg-text-secondary text-white shadow-sm text-center'>
<th className='p-2'>name</th>
<th className='p-2'>phone</th>
</tr>
</thead>
<tbody>
{currentUsers.map((item, index) =>
<tr key={item.id} className={index % 2 === 0 ? 'bg-white shadow-sm text-center' : 'bg-text bg-opacity-5 shadow-sm text-center'}>
<td className='text-text text-sm p-2'>{item.name}</td>
<td className='text-text text-sm p-2'>{item.phone}</td>
</tr>
)}
</tbody>
</table>
)
}
I have been successful in receiving the search term in the back-end, but I don't know how to apply this on the selected option as well. I tried adding onClick() and onChange() on each option and save the state, but I wasn't successful. How can I do this?

Your onChange should be on the select tag. Here is what I did.
import React, { useState, useEffect } from "react";
const Table = () => {
const navigate = useNavigate()
const [users, setUsers] = useState([]);
const [currentUsers, setCurrentUsers] = useState([]);
const [search, setSearch] = useState("");
const [column, setColumn] = useState(""); //for saving the selected option
useEffect(async () => {
try {
const response = await getUsers(search);
setUsers(response.data.users);
} catch (error) { }
}, [search]);
return (
<>
<input
type="text"
placeholder="search.."
onChange={(e) => setSearch(e.target.value)}
value={search}
/>
// added here
<select
aria-label=".form-select-sm example"
onChange={(e) => {
setColumn(e.target.value);
console.log(e.target.value);
}}
>
<option selected value="1">
all
</option>
<option value="2">name</option>
<option value="3">phone</option>
</select>
<table className="w-full border-separate rounded-md">
<thead>
<tr className="bg-text-secondary text-white shadow-sm text-center">
<th className="p-2">name</th>
<th className="p-2">phone</th>
</tr>
</thead>
<tbody>
{currentUsers.map((item, index) => (
<tr
key={item.id}
className={
index % 2 === 0
? "bg-white shadow-sm text-center"
: "bg-text bg-opacity-5 shadow-sm text-center"
}
>
<td className="text-text text-sm p-2">{item.name}</td>
<td className="text-text text-sm p-2">{item.phone}</td>
</tr>
))}
</tbody>
</table>
</>
);
};

Related

Filter function by name React

I need a function to filter by name, The data comes from my Laravel API, I wanted to make a filter on the screen to search for the account name. I am new to React.
import Table from "react-bootstrap/Table";
import axios from "axios";
import { Link } from "react-router-dom";
import { useState, useEffect } from "react";
import Form from "react-bootstrap/Form";
import Button from "react-bootstrap/Button";
const endpoint = "http://localhost:8000/api";
const AccountShow = () => {
const [accounts, setAccounts] = useState([]);
useEffect(() => {
getAllAccounts();
}, []);
const getAllAccounts = async () => {
const response = await axios.get(`${endpoint}/accounts`);
setAccounts(response.data);
};
const deleteAccount = async (id) => {
await axios.delete(`${endpoint}/account/${id}`);
getAllAccounts();
};
return (
<div className="d-grid gap-2">
<div className="row">
<div className="col-8">
<Form className="d-flex m-1">
<Form.Control
type="search"
placeholder="Filtro"
className="me-2"
aria-label="Search"
/>
<Button variant="outline-secondary">Search</Button>
</Form>
</div>
<div className="col-4">
<Link
to="/account/create"
className="col-11 btn btn-outline-primary m-1 "
>
Create
</Link>
</div>
</div>
<Table hover className="">
<thead>
<tr>
<th scope="col">#</th>
<th className="col-2" scope="col">
Nome
</th>
<th className="col-2" scope="col">
Razão Social
</th>
<th scope="col">Status da Conta</th>
<th scope="col">Setor</th>
<th scope="col">Segmento Atuacao</th>
<th scope="col">Natureza Juridica</th>
<th scope="col">Capital</th>
<th scope="col">Funcionarios</th>
<th className="text-center" scope="col">
Ações
</th>
</tr>
</thead>
<tbody>
{accounts.map((account) => (
<tr key={account.id}>
<th>{account.id}</th>
<td>{account.nome}</td>
<td>{account.razaoSocial}</td>
<td>{account.statusConta}</td>
<td>{account.setor}</td>
<td>{account.segmentoAtuacao}</td>
<td>{account.naturezaJuridica}</td>
<td>{account.capital}</td>
<td>{account.funcionarios}</td>
<td className="text-center">
<Link
to={`edit/${account.id}`}
className="btn btn-outline-warning"
>
Editar
</Link>
<button
onClick={() => deleteAccount(account.id)}
className="btn btn-outline-danger m-1"
>
Deletar
</button>
</td>
</tr>
))}
</tbody>
</Table>
</div>
);
};
export default AccountShow;
This is a correct way to filter.
import Table from "react-bootstrap/Table";
import axios from "axios";
import { Link } from "react-router-dom";
import { useState, useEffect } from "react";
import Form from "react-bootstrap/Form";
import Button from "react-bootstrap/Button";
const endpoint = "http://localhost:8000/api";
const AccountShow = () => {
const searchQuery = useState("");
const [accounts, setAccounts] = useState([]);
const [accountToShow, setAccountsToShow] = useState([]);
useEffect(() => {
setAccountsToShow(accounts.filter((account) => /*filter by a specific parameter here depending on what you want to filter it by; by the account.nome field?*/ account.nome.includes(searchQuery)));
}, [accounts, searchQuery]);
useEffect(() => {
getAllAccounts();
}, []);
const getAllAccounts = async () => {
const response = await axios.get(`${endpoint}/accounts`);
setAccounts(response.data);
};
const deleteAccount = async (id) => {
await axios.delete(`${endpoint}/account/${id}`);
getAllAccounts();
};
return (
<div className="d-grid gap-2">
<div className="row">
<div className="col-8">
<Form className="d-flex m-1">
<Form.Control
onChange={({target}) => setSearchQuery(target.value)}
value={searchQuery}
type="search"
placeholder="Filtro"
className="me-2"
aria-label="Search"
/>
<Button variant="outline-secondary">Search</Button>
</Form>
</div>
<div className="col-4">
<Link
to="/account/create"
className="col-11 btn btn-outline-primary m-1 "
>
Create
</Link>
</div>
</div>
<Table hover className="">
<thead>
<tr>
<th scope="col">#</th>
<th className="col-2" scope="col">
Nome
</th>
<th className="col-2" scope="col">
Razão Social
</th>
<th scope="col">Status da Conta</th>
<th scope="col">Setor</th>
<th scope="col">Segmento Atuacao</th>
<th scope="col">Natureza Juridica</th>
<th scope="col">Capital</th>
<th scope="col">Funcionarios</th>
<th className="text-center" scope="col">
Ações
</th>
</tr>
</thead>
<tbody>
{accountsToShow.map((account) => (
<tr key={account.id}>
<th>{account.id}</th>
<td>{account.nome}</td>
<td>{account.razaoSocial}</td>
<td>{account.statusConta}</td>
<td>{account.setor}</td>
<td>{account.segmentoAtuacao}</td>
<td>{account.naturezaJuridica}</td>
<td>{account.capital}</td>
<td>{account.funcionarios}</td>
<td className="text-center">
<Link
to={`edit/${account.id}`}
className="btn btn-outline-warning"
>
Editar
</Link>
<button
onClick={() => deleteAccount(account.id)}
className="btn btn-outline-danger m-1"
>
Deletar
</button>
</td>
</tr>
))}
</tbody>
</Table>
</div>
);
};
export default AccountShow;
You can filter data using
useMemo()
const [accounts, setAccounts] = useState([]);
const [query, setQuery] = useState('');
const filterData = useMemo(() => {
if (accounts && accounts?.length > 0) {
return accounts.filter(item =>
item?.name
.toLocaleLowerCase('en')
.includes(query.trim().toLocaleLowerCase('en')),
);
}
}, [accounts, query]);
you can set query using textbox change event

Table closing after populating data passed as props from a modal

I'm passing data from am AddItem modal in react to a table in the NewInvoice component. The data is being populated to the table successfully but modal does not close after clicking the save button. Kindly assist on what i could be missing on this.
NewInvoice.js
const [itemOpen, setitemOpen] = useState(false);
<div className="new-invoice-client">
<FormDataTable itemOpen={itemOpen}/>
</div>
<div
className="new-item-links"
style={{ marginLeft: "35px", marginTop: "35px" }}
>
<Button onClick={() => setitemOpen(true)}>
<BsPlus />
Add an Item
{itemOpen && <AddItem setitemOpen={setitemOpen} />}
</Button>
</div>
The <FormInvoiceTable/> is passed to the NewInvoice parent component as shown below.
FormInvoieTable.js
function FormDataTable(props) {
const [tableData, setTableData] = useState([]);
// console.log(tableData)
const tableRows = tableData.map((value, index) => {
return (
<tr key={index}>
<td>{value.item}</td>
<td>{value.amount}</td>
<td>{value.rate}</td>
<td>{value.quantity}</td>
<td>{value.description}</td>
</tr>
);
});
const addRows = (data) => {
const totalData = tableData.length;
data.id = totalData + 1;
const updatedtableData = [...tableData];
updatedtableData.push(data);
setTableData(updatedtableData);
};
return (
<React.Fragment>
<table className="table">
<thead>
<tr>
<th>Item</th>
<th>Description</th>
<th>Qty</th>
<th>Rate</th>
<th>Amount</th>
</tr>
</thead>
<tbody>{tableRows}</tbody>
</table>
<AddItem func={addRows}/>}
</React.Fragment>
);
}
AddItem.js Modal
function AddItem(props) {
const [item, setItem] = useState("");
const [amount, setAmount] = useState("");
const [rate, setRate] = useState("");
const [quantity, setQuantity] = useState("");
const [description, setDescription] = useState("");
const clearState = () => {
setItem("");
setAmount("");
setRate("");
setQuantity("");
setDescription("");
};
const handleSubmit = (event) => {
event.preventDefault();
const formInputData = {
item,
amount,
rate,
quantity,
description,
};
props.func(formInputData);
// clearState();
props.setitemOpen(false)
};
return (
<div className="modalBackground">
<div className="modalContainer">
<div className="title">
<h1>New Item</h1>
</div>
<div className="modal-form-container">
<form className="register-form">
<input
className="register-input"
name="item"
onChange={(e) => setItem(e.target.value)}
value={item}
placeholder="Item"
/>
<input
className="register-input"
name="amount"
value={amount}
placeholder="Amount"
onChange={(e) => setAmount(e.target.value)}
/>
<input
className="register-input"
placeholder="Rate"
name="rate"
value={rate}
onChange={(e) => setRate(e.target.value)}
/>
<input
className="register-input"
name="quantity"
placeholder="Quantity"
value={quantity}
onChange={(e) => setQuantity(e.target.value)}
/>
<input
className="register-input"
style={{ width: "600px", height: "80px" }}
type="text"
value={description}
placeholder="Description"
onChange={(e) => setDescription(e.target.value)}
/>
<div className="modal-buttons" style={{ justifyContent: "center" }}>
<button onClick={handleSubmit}>Save</button>
<button onClick={() => props.setitemOpen(false)}>cancel</button>
</div>
</form>
</div>
</div>
</div>
);
}
Your are creating component <AddItem/> two times.
When you create it in FormDataTable component you don't pass it prop setitemOpen. You are passing only addRows function as a prop :
<AddItem func={addRows}/>
One solution would be to pass setitemOpen={setitemOpen} prop to FormDataTable component and call it in addRow method with argument false. Also, remove AddItem component from NewInvoice component and create it only in FormDataTable component based on itemOpen
Here is code snippet:
NewInvoice.jsx
import React from "react";
import FormDataTable from "./FormInvoieTable";
import { useState } from "react";
import Button from "#mui/material/Button";
export default function NewInvoice(props) {
const [itemOpen, setitemOpen] = useState(false);
return (
<>
<div className="new-invoice-client">
<FormDataTable itemOpen={itemOpen} setitemOpen={setitemOpen} />
</div>
<div
className="new-item-links"
style={{ marginLeft: "35px", marginTop: "35px" }}
>
<Button onClick={() => setitemOpen(true)}>Add an Item</Button>
</div>
</>
);
}
Then in FormDataTable component, modify addRows method like this:
FormDataTable.jsx
import React from "react";
import AddItem from "./AddItem";
import { useState } from "react";
export default function FormDataTable(props) {
const [tableData, setTableData] = useState([]);
const { itemOpen } = props;
const tableRows = tableData.map((value, index) => {
return (
<tr key={index}>
<td>{value.item}</td>
<td>{value.amount}</td>
<td>{value.rate}</td>
<td>{value.quantity}</td>
<td>{value.description}</td>
</tr>
);
});
const addRows = (data) => {
const totalData = tableData.length;
data.id = totalData + 1;
const updatedtableData = [...tableData];
updatedtableData.push(data);
setTableData(updatedtableData);
props.setitemOpen(false);
};
return (
<React.Fragment>
<table className="table">
<thead>
<tr>
<th>Item</th>
<th>Description</th>
<th>Qty</th>
<th>Rate</th>
<th>Amount</th>
</tr>
</thead>
<tbody>{tableRows}</tbody>
</table>
{itemOpen && <AddItem func={addRows} />}
</React.Fragment>
);
}
AddItem.jsx
import React from "react";
import { useState } from "react";
export default function AddItem(props) {
const [item, setItem] = useState("");
const [amount, setAmount] = useState("");
const [rate, setRate] = useState("");
const [quantity, setQuantity] = useState("");
const [description, setDescription] = useState("");
console.log(props);
const clearState = () => {
setItem("");
setAmount("");
setRate("");
setQuantity("");
setDescription("");
};
const handleSubmit = (event) => {
event.preventDefault();
const formInputData = {
item,
amount,
rate,
quantity,
description,
};
props.func(formInputData);
// clearState();
};
return (
<div className="modalBackground">
<div className="modalContainer">
<div className="title">
<h1>New Item</h1>
</div>
<div className="modal-form-container">
<form className="register-form">
<input
className="register-input"
name="item"
onChange={(e) => setItem(e.target.value)}
value={item}
placeholder="Item"
/>
<input
className="register-input"
name="amount"
value={amount}
placeholder="Amount"
onChange={(e) => setAmount(e.target.value)}
/>
<input
className="register-input"
placeholder="Rate"
name="rate"
value={rate}
onChange={(e) => setRate(e.target.value)}
/>
<input
className="register-input"
name="quantity"
placeholder="Quantity"
value={quantity}
onChange={(e) => setQuantity(e.target.value)}
/>
<input
className="register-input"
style={{ width: "600px", height: "80px" }}
type="text"
value={description}
placeholder="Description"
onChange={(e) => setDescription(e.target.value)}
/>
<div className="modal-buttons" style={{ justifyContent: "center" }}>
<button onClick={handleSubmit}>Save</button>
<button onClick={() => props.setitemOpen(false)}>cancel</button>
</div>
</form>
</div>
</div>
</div>
);
}

How do I display data from my json file that match my filters

I'm creating a multi steps form in React and I want a page (Filters.jsx) in my form, that returns me all the menus name (contained in data.json) that matches my filters ( beaf, chicken, vegetables), but I don't kow how to do that.
import React from "react";
export default function Filter() {
return (
<div className="flex flex-col">
<div className=" w-full mx-2 flex-1">
<div className="font-bold h-6 mt-3 text-gray-600 leading-8 uppercase ">
{" "}
Norms
</div>
<tbody className="bg-white my-2 p-1 flex borer border-gray-200 rounded text-gray-500">
<tr>
<td className="font-bold h-8 mt-5 leading-8 uppercase ">
<td>
<input type="checkbox" value="beaf" className="w-8 h-3" /> beaf
</td>
<td>
<input type="checkbox" value="chicken" className="w-8 h-3" />
chicken
</td>
<td>
<input type="checkbox" value="vegetables" className="w-8 h-3" />
vegetables
</td>
</td>
</tr>
</tbody>
</div>
</div>
);
}
Here is the link of my sandbox ( browse /menu/form to see the form): https://codesandbox.io/s/unruffled-river-ktoic8?
What I tried:
export default function Filters() {
//Filters events
const ref = [
{ name: "beaf" },
{ name: "chicken" },
{ name: "vegetables" }
]
const [norms, setNorms] = useState([]);
useEffect(() => {
setNorms(ref);
}, []);
const handleChange = (e) => {
const { name, checked } = e.target;
let tempR = norms.map((r) =>
r.name === name ? { ...r, isChecked: checked } : r
);
setNorms(tempR);
}
return (
<div>
<form className="form w-100">
{
norms.map((e, index) => (
<div className="form-check" key={index}>
<input
type="checkbox"
className="form-check-input"
name={e.name}
checked={e?.isChecked || false}
onChange={handleChange}
/>
<label className="form-check-label ms-2">{e.name}</label>
</div>
))
}
</form >
</div>
)
I suggest using an object or Map to hold the filter values where the filter name is the key and the checked value is the value.
const [filters, setFilters] = React.useState({});
Create a handler that sets the checked value for a specific input by name.
const changeHandler = (e) => {
const { name, checked } = e.target;
setFilters((filters) => ({
...filters,
[name]: checked
}));
};
Render the inputs and set the checked prop from state.
{["beef", "chicken", "vegetables"].map((name) => (
<td key={name}>
<label>
<input
type="checkbox"
checked={filters[name]}
onChange={changeHandler}
name={name}
className="w-8 h-3"
/>
{name}
</label>
</td>
))}
And then filter/map the data, all inline.
import data from "../../data.json";
...
{data
.filter((item) => {
// get array of enabled filter keys
const filterEntries = Object.entries(filters)
.filter(([, value]) => Boolean(value))
.map(([key]) => key);
// some filter enabled
if (filterEntries.length) {
// check proteins
if (filters.beef || filters.chicken) {
return item.dishes.some((dish) =>
filterEntries.includes(dish.meat)
);
}
// check vegetables
if (filters.vegetables) {
return item.dishes.some((dish) => !!dish.vegetables);
}
}
// no filter enabled, return all elements
return true;
})
.map((item) => (
<tr key={item.id}>
.... map data item properties here ...
</tr>
))}

React-Redux: Data not read during initial render in useState

I am trying to get a list of data called packages and put it in a table. Added filter and sorting to it.
I get packages from pakageList reducer
Assign to data state
Then add soring and filtering logic and assign data to variable called filteredPackages
Everything seems fine but when the page initially loads the contents of the table is empty i.e, the data state is empty. This happens while adding or deleting a package and render occurs as well.
Once I go back and come to this screen again the data loads. The data is present in the packages which I get from reducers but it does not get assigned to the data state.
Can anyone try checking and let me know what can be done here. Sorry if my code is not good. Thanks in advance.
Skipping code which is not necessary
const PackageScreen = ({ match }) => {
const [ order, setOrder ] = useState('ASC')
const packageList = useSelector(state => state.packageList)
const { loading, error, packages } = packageList
const packageCreate = useSelector(state => state.packageCreate)
const { loading:loadingCreate , error:errorCreate , success: successCreate, package: createdPackage } = packageCreate
const packageDelete = useSelector(state => state.packageDelete)
const { loading:loadingDelete , error:errorDelete , success: successDelete } = packageDelete
const [ data, setData ] = useState([])
useEffect(() => {
dispatch({type: PACKAGE_CREATE_RESET})
if(!userInfo || !userInfo.isAdmin){
navigate('/')
}
setName('')
setMaxDays(0)
setMaxUsers(0)
dispatch(listPackages())
setData(packages)
}, [dispatch, userInfo, successCreate, successDelete, navigate] )
const sorting = (col) => {
if(order === 'ASC'){
const sorted = [...data].sort((a,b) =>
a[col].toString().toLowerCase() > b[col].toString().toLowerCase() ? 1 : -1
)
setData(sorted)
setOrder('DSC')
}
if(order === 'DSC'){
const sorted = [...data].sort((a,b) =>
a[col].toString().toLowerCase() < b[col].toString().toLowerCase() ? 1 : -1
)
setData(sorted)
setOrder('ASC')
}
}
function search(data) {
return data.filter((pack) =>
pack.packageName.toLowerCase().indexOf(q.toLowerCase()) > -1
)
}
const filteredPackages = search(data)
const submitHandler = (e) =>{
e.preventDefault()
dispatch(createPackage({
packageName: name,
maxDaysAllowed : maxDays * 30,
maxUserAllowed : maxUsers
}))
}
const deleteHandler = (id) =>{
if(window.confirm('Are you sure you want to delete?')){
dispatch(deletePackage(id))
}
}
return(
<>
<Link to='/' className='btn btn-dark my-3'>Go Back</Link>
<h1>Add Package</h1>
<Form onSubmit={submitHandler}>
<Row className='my-3' >
<Col>
<Form.Group className="mb-3" controlId='name'>
<FloatingLabel controlId="floatingInput" label="Package Name" className="mb-3">
<Form.Control type="text" placeholder="Package name"
value={name}
onChange = {(e)=> setName(e.target.value)}
/>
</FloatingLabel>
</Form.Group>
</Col>
<Col>
<Form.Group controlId='maxUsers'>
<FloatingLabel controlId="floatingSelect" label="Max. allowed users">
<Form.Control as='select' value={maxUsers}
onChange={(e) => setMaxUsers(e.target.value)}>
{/*<Form.Select aria-label="Floating label select example">*/}
<option>Select number of users</option>
<option value="3">3</option>
<option value="5">5</option>
<option value="10">10</option>
{/*</Form.Select>*/}
</Form.Control>
</FloatingLabel>
</Form.Group>
</Col>
<Col>
<Form.Group controlId='maxDays'>
<FloatingLabel controlId="floatingSelect" label="Package Limit">
<Form.Control as='select' value={maxDays}
onChange={(e) => setMaxDays(e.target.value)}>
{/*<Form.Select aria-label="Floating label select example">*/}
<option>Select Period</option>
<option value="1">1 Month</option>
<option value="3">3 Months</option>
<option value="6">6 Months</option>
<option value="12">1 year</option>
{/*</Form.Select>*/}
</Form.Control>
</FloatingLabel>
</Form.Group>
</Col>
</Row>
<Button type='submit' variant='primary'>
Save
</Button>
</Form>
<h2 className='mt-4'>Package List</h2>
<div className='d-flex'>
<div className='p-2'>
<div className='searchTable'>
<InputGroup className="me-2 my-2">
<InputGroup.Text>Search</InputGroup.Text>
<FormControl aria-label="Search"
value={q} onChange={(e) => setQ(e.target.value)}
/>
</InputGroup>
</div>
</div>
</div>
{ loading ? <Loader />
: error ? <Message variant='danger'>{error}</Message>
: (
<div>
<Table striped bordered hover responsive='md' className='table-sm bg-light' id="table-to-xls">
<thead>
<tr>
<th onClick={() => sorting('packageName')} ><span className='btn'>Package Name</span></th>
<th onClick={() => sorting('maxUserAllowed')} ><span className='btn'>Maximum Users</span></th>
<th onClick={() => sorting('maxDaysAllowed')} ><span className='btn'>Maximum Days</span></th>
<th><span className='btn'>Action</span></th>
</tr>
</thead>
<tbody>
{filteredPackages.map(pack => (
<tr key={pack._id} >
<td>{pack.packageName}</td>
<td>{pack.maxUserAllowed}</td>
<td>{pack.maxDaysAllowed}</td>
<td>
{/*<LinkContainer to={`/admin/product/${product._id}/edit`}>*/}
<Button variant='info' className='btn-sm mx-1' disabled>
<i className='fas fa-edit'></i>
</Button>
{/*</LinkContainer>*/}
<Button variant='danger' className='btn-sm'
onClick={()=> deleteHandler(pack._id)}
>
<i className='fas fa-trash'></i>
</Button>
</td>
</tr>
)) }
</tbody>
</Table>
</div>
)
}
</>
)
}
export default PackageScreen
data and filteredPackage both are empty at initial renders.
I tried the below in useEffect but no luck
useEffect(() => {
dispatch({type: PACKAGE_CREATE_RESET})
if(!userInfo || !userInfo.isAdmin){
navigate('/')
}
setName('')
setMaxDays(0)
setMaxUsers(0)
dispatch(listPackages())
**const fetchData = async()=>{
await setData(packages)
}
fetchData()**
}, [dispatch, userInfo, successCreate, successDelete, navigate] )
Please let me know if you need further details.
Make a const for packages and assign this to your data state
const packages = useSelector(state => state.packageList.packages)
...
const [ data, setData ] = useState(packages)
and write a useEffect that updates your data state when ever your package store value renders
useEffect(()=>{
setData([...packages])
},[packages])

Update input label which is render by array map in REACTJS

Hope you guys are fine.
I have the next code for dynamically show the quantity of each selected product
import React, { useState, useEffect } from 'react';
import db from '../firebase';
//const Swal = window.Swal;
const NewSale = () => {
const [products, setProducts] = useState([]);
const [selectedProducts, setSelectedProducts] = useState([]);
useEffect(() => {
if(products.length === 0){
db.collection('products').get().then((querySnapshot) => {
const docs = [];
querySnapshot.forEach((doc) => {
docs.push({
id: doc.id,
...doc.data()
});
});
docs.sort((a, b)=> a.name.localeCompare(b.name));
setProducts(docs);
});
}
});
const handleSelectChange = (e) => {
const value = e.target.value;
if(value){
const selectedProduct = products.filter(item => item.id === value)[0];
setSelectedProducts(selectedProducts => [...selectedProducts, {
id: value,
name: selectedProduct.name,
quantity: 1
}]);
}
}
const handleRangeChange = (target, index) => {
const currentValue = parseInt(target.value);
let currentArrayValue = selectedProducts;
currentArrayValue[index].quantity = currentValue;
setSelectedProducts(currentArrayValue);
}
const handleCancelButton = () => {
setSelectedProducts([]);
}
return (
<React.Fragment>
<div className='container'>
<h1 className='display-3 text-center'>New Sale</h1>
<div className='row'>
<div className='col'>
<div className='mb-3'>
<label htmlFor='product' className='form-label fs-3'>Service</label>
<select id='product' onChange={handleSelectChange} className='form-select form-select-lg' multiple aria-label='multiple select service'>
{products.length !== 0?
products.map(item => <option key={item.id} value={item.id}>{item.name}</option>) : <option>No product registered</option>
}
</select>
</div>
</div>
</div>
<div className='row mt-4'>
<div className='col'>
<table className='table caption-top'>
<caption>Sell List</caption>
<thead>
<tr>
<th scope='col'>#</th>
<th scope='col'>Product</th>
<th scope='col'>Quantity</th>
</tr>
</thead>
<tbody>
{selectedProducts.length !== 0?
selectedProducts.map((item, index) => (
<tr key={index}>
<th scope='row'>{(index + 1)}</th>
<td>{item.name}</td>
<td>
<label htmlFor={`customRange-${index}`} className='form-label'>{item.quantity} Units</label>
<input
type='range'
className='form-range'
value={item.quantity}
onChange={({target}) => handleRangeChange(target, index)}
min='1'
max='100'
step='1'
id={`customRange-${index}`}/>
</td>
</tr>
)) :
<tr>
<th className='text-center' colSpan='3'>Nothing selected!</th>
</tr>
}
</tbody>
</table>
</div>
</div>
<div className='row mt-2'>
<div className='col'>
<button className='btn btn-success'>Save</button>
</div>
<div className='col'>
<button className='btn btn-warning' onClick={handleCancelButton}>Cancel</button>
</div>
</div>
</div>
</React.Fragment>
)
};
export default NewSale;
The code shows this... I do not know if I'm allowed to do this kind of operations because I'm adding events every time I select a product so, I'm not sure this is the best way to do it.
And the problem is that I'm getting this unexpected result,
What I want to do is show the current Quantity for each selected item,
Thanks!!

Categories

Resources