React count value of array and calculate total price - reactjs

The moment an item is selected from the dropdown, the item 'price' of the object is used in the 'countTotalPrice' function. In this function it is the intention that every time an item is selected, the price of the new item is added to the already existing series.
At this time, the function pushes the value to the array, but it constantly overwrites the previous value instead of adding the new value to the previous value.
What I want to achieve is that when someone chooses a treatment and the row is created, all the prices of the created rows are added together to a total amount.
The code:
import React from "react";
import { useState } from 'react';
import { makeStyles } from "#material-ui/core/styles";
import styles from "assets/jss/material-dashboard-react/views/dashboardStyle.js";
import { Container } from "react-bootstrap";
import { Row } from "react-bootstrap";
import { Col } from "react-bootstrap";
import Close from '#material-ui/icons/Close';
import { render } from "react-dom";
const useStyles = makeStyles(styles);
export default function ChaskDesk() {
const employee = ["Robin","Raoul","Joppe "];
const service = [{
id: 1,
name: 'Knippen',
price: 11.00
},
{
id: 2,
name: 'Scheren',
price: 10.00
},
{
id: 3,
name: 'Wassen',
price: 12.00
}]
const counting = [1,2,3,4,5,6];
const gender = ["man", "vrouw", "kind"];
const client = ["Passant"];
const [employeeOrder, setEmployeeOrder] = useState('');
const [serviceOrder, setServiceOrder] = useState([]);
//const serviceOrder = [];
const countingOrder = [];
const genderOrder = [];
const clientOrder = "";
const [payment, setPayment] = useState([]);
//const payment = 0;
const classes = useStyles();
const handelChangeGender = function(event){
genderOrder.push(event.target.value);
};
//this function
const handelChangeService = function(event){
for(var i = 0; i < service.length; i++) {
if (service[i].id == event.target.value) {
setServiceOrder([...serviceOrder,{name: service[i].name, price: service[i].price, id:service[i].id}]);
countTotalPrice(service[i].price);
}
}
};
//this function
const countTotalPrice = function(price){
const counts = [];
counts.push(price);
console.log(counts);
};
const popService = function(event){
setServiceOrder(serviceOrder.filter(item => item.id !== event));
};
const handelChangeEmployee = function(event) {
setEmployeeOrder(event.target.value)
};
return (
<div>
<Container className={classes.containerPixelActive}>
<h3>Afrekenen</h3>
<Row className={classes.tablePixelRow}>
<Col md={8} className={classes.rowChashdesk}>
<form>
<Row>
<Col md={6}>
<label>
Klant:
</label>
<br/>
<select >
{
client.map(function(item, i){
return <option key={i} value={item}>{item}</option>
})
}
</select>
</Col>
</Row>
<Row>
<Col md={6}>
<div className={classes.rowOfForm}>
<label>
Gender:
</label>
<br/>
<select onChange={handelChangeGender}>
{
gender.map(function(item, i){
return <option key={i} value={item}>{item}</option>
})
}
</select>
</div>
</Col>
</Row>
<Row>
<Col md={6}>
<div className={classes.rowOfForm}>
<label>
Behandeling:
</label>
<br/>
<select onChange={handelChangeService}>
{
service.map(function(item){
return <option key={item.id} value={item.id}>{item.name}</option>
})
}
</select>
</div>
</Col>
<Col md={6}>
<div className={classes.rowOfForm}>
<label>
Medewerker:
</label>
<br/>
<select onChange={handelChangeEmployee}>
{
employee.map(function(item, i){
return <option key={i} value={item}>{item}</option>
})
}
</select>
</div>
</Col>
</Row>
{
serviceOrder.map(function(item, i){
console.log(item)
return <Row key={i} >
<Col md={6}>
<div className={classes.rowOfForm}>
<label>
Verkregen behandeling:
</label>
<br/>
<input type="text" name="name" value={item.name}/>
</div>
</Col>
<Col md={2}>
<div className={classes.rowOfForm}>
<label>
Aantal:
</label>
<br/>
<select>
{
counting.map(function(item, i){
return <option key={i} value={item}>{item}</option>
})
}
</select>
</div>
</Col>
<Col md={2}>
<div className={classes.rowOfForm}>
<label>
Prijs:
</label>
<br/>
<input type="text" name="name" value={item.price}/>
</div>
</Col>
<Col md={2}>
<div className={classes.rowIcon}>
<Close size={20} onClick={() => popService(item.id)}></Close>
</div>
</Col>
</Row>
})}
</form>
</Col>
<Col md={3} className={classes.rowChashdesk}>
<h5>Totaal overzicht</h5>
<h6>Medewerker</h6>
<p>{employeeOrder}</p>
<h6>Behandeling</h6>
<ul>
{
serviceOrder.map(function(item, i){
return <li class="listTreatment" key={i}>{item.name}</li>
})
}
</ul>
<h6>Aantal</h6>
<p>{countingOrder}</p>
<h6>Klant</h6>
<p>{clientOrder}</p>
<h6>Te betalen</h6>
<p>{countTotalPrice}</p>
</Col>
</Row>
</Container>
</div>
);
}

Each time the function runs you are making new counts array.
const countTotalPrice = function(price){
const counts = [];
counts.push(price);
console.log(counts);
};
you should declare counts outside this function
please try to decalre it as state
const [counts, setCounts] = useState([]);
//.....
const countTotalPrice = function(price){
let newCounts = counts
newCounts.push(price);
setCounts(newCounts );
console.log(counts);
};

Related

setState on updating values on page

For the code below when the data is sent from the other page with the state I am trying to set default values and have the text be reflected one the page. The data is being successfully sent to the page but the constants aren't being updated with the useState hook. I checked several sources and still couldn't find a solution that helped this specific bug
Picture of the page
import React, {useEffect} from 'react';
import {Col, Container, Form, Row} from "react-bootstrap";
import Header from "./Header";
import Footer from "./Footer";
import {useState} from "react";
import {useLocation} from "react-router-dom";
import {render} from "react-dom";
const Bookings = () => {
/*Constants for ticket pricing*/
const [kingston_ticket_cost] = useState(180);
const [portland_ticket_cost] = useState(200);
const [negril_ticket_cost] = useState(280);
const [ochorios_ticket_cost] = useState(240);
const [montegobay_ticket_cost] = useState(260);
/*Initialize variables with initial state*/
const [fname, setFname] = useState("");
const [lname, setLname] = useState("");
const [phone, setPhone] = useState("");
const [email, setEmail] = useState("");
const [adultText, setAdultText] = useState("Adult");
const [adultTotal, setAdultTotal] = useState(0);
const [childText, setChildText] = useState("Child");
const [childTotal, setChildTotal] = useState(0);
const [total, setTotal] = useState(0);
const [adult_tickets, setAdultTickets] = useState(0);
const [children_tickets, setChildrenTickets] = useState(0);
const [kingston, setKingston] = useState(false);
const [portland, setPortland] = useState(false);
const [negril, setNegril] = useState(false);
const [ochorios, setOchorios] = useState(false);
const [montegobay, setMontegobay] = useState(false);
/*get information sent through artificial URL*/
let location = useLocation();
/*Set initial values*/
const set_init_val = (state) => {
let priceCounter = 0;
/*Set checkboxes based on what is sent over*/
if (location.state != null) {
setAdultTickets((adult_tickets) => location.state.adult_s);
setChildrenTickets((children_tickets) => location.state.child_s);
if (location.state.destination_s === "kingston" || location.state.destination_s === "all") {
setKingston(true);
priceCounter += kingston_ticket_cost;
if (priceCounter == 0) {
alert("Error : state not updated");
}
}
if (location.state.destination_s === "portland" || location.state.destination_s === "all") {
setPortland(true);
priceCounter += portland_ticket_cost;
}
if (location.state.destination_s === "negril" || location.state.destination_s === "all") {
setNegril(true);
priceCounter += negril_ticket_cost;
}
if (location.state.destination_s === "ochorios" || location.state.destination_s === "all") {
setOchorios(true);
priceCounter += ochorios_ticket_cost;
}
if (location.state.destination_s === "montegobay" || location.state.destination_s === "all") {
setMontegobay(true);
priceCounter += montegobay_ticket_cost;
}
setAdultTotal((adultTotal) => adult_tickets * priceCounter);
setChildTotal((childTotal) => children_tickets * ((adultTotal / adult_tickets) / 2));
setTotal((total) => adultTotal + childTotal);
} else {
return
}
return total;
}
useEffect(() => {
set_init_val()
}, []);
return (
<>
<Header/>
<Container>
<h1 className="booking_title">Book Your Next Adventure</h1>
<Form>
<Row>
<Col style={{padding: "50px"}}>
<h1 className="formheader">Booking Information</h1>
<div style={{padding: "15px"}}>
<Form.Group className={"mb-3"} style={{fontWeight: "bold"}}>
<Form.Label>First Name</Form.Label>
<Form.Control placeholder={"First name"} style={{width: "500px"}}/>
</Form.Group>
<Form.Group className={"mb-3"} style={{fontWeight: "bold"}}>
<Form.Label>Last Name</Form.Label>
<Form.Control placeholder={"Last name"} style={{width: "500px"}}/>
</Form.Group>
<Form.Group className={"mb-3"} style={{fontWeight: "bold"}}>
<Form.Label>Phone</Form.Label>
<Form.Control name={"phone"} placeholder={"000-000-0000"}
style={{width: "500px"}}/>
</Form.Group>
<Form.Group className={"mb-3"} style={{fontWeight: "bold"}}>
<Form.Label>Email</Form.Label>
<Form.Control placeholder={"email#email.com"}
style={{width: "500px"}}/>
</Form.Group>
<Form.Label style={{fontWeight: "bold"}}>Destinations</Form.Label>
{['checkbox'].map((type) => (
<div key={`default-${type}`} className="mb-3">
<Form.Check
id={`default-${type}`}
label={`Kingston $180`}
checked={kingston}
onChange={(e) => setKingston(!kingston)}
/>
<Form.Check
id={`default-${type}`}
label={`Portland $200`}
checked={portland}
onChange={(e) => setPortland(!portland)}
/>
<Form.Check
id={`default-${type}`}
label={`Negril $280`}
checked={negril}
onChange={(e) => setNegril(!negril)}
/>
<Form.Check
id={`default-${type}`}
label={`Ocho Rios $240`}
checked={ochorios}
onChange={(e) => setOchorios(!ochorios)}
/>
<Form.Check
id={`default-${type}`}
label={`Montego Bay $260`}
checked={montegobay}
onChange={(e) => setMontegobay(!montegobay)}
/>
</div>
))}
<Row>
<Col>
<Form.Label style={{fontWeight: "bold"}}>Adult</Form.Label>
<Form.Select value={adult_tickets}
onChange={(e) => setAdultTickets(parseInt(e.target.value))}>
<option>0</option>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
</Form.Select>
</Col>
<Col>
<Form.Label style={{fontWeight: "bold"}}>Children</Form.Label>
<Form.Select value={children_tickets}
onChange={(e) => setChildrenTickets(parseInt(e.target.value))}>
<option>0</option>
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
<option>6</option>
</Form.Select>
</Col>
<Col>
<Form.Label style={{fontWeight: "bold"}}>Date</Form.Label>
<Form.Control type={"date"}/>
</Col>
</Row>
</div>
</Col>
<Col className={"paycol"} style={{padding: "50px"}}>
<h1 className="formheader">Payment Information</h1>
<div className={"totals"} style={{padding: "15px"}}>
<Row>
<Col>{adultText}</Col>
<Col>${adultTotal}</Col>
</Row>
<Row>
<Col>{childText}</Col>
<Col>${childTotal}</Col>
</Row>
<Row>
<Col>Total</Col>
<Col>${total}</Col>
</Row>
</div>
<div style={{marginTop: "50px"}}>
<Form.Label style={{fontWeight: "bold"}}>Credit/Debit Card number</Form.Label>
<Form.Control placeholder={"0000 0000 0000 0000"}/>
<Row style={{marginTop: "50px"}}>
<Col>
<Form.Label style={{fontWeight: "bold"}}>Exp month</Form.Label>
<Form.Select>
<option value="01">01</option>
<option value="02">02</option>
<option value="03">03</option>
<option value="04">04</option>
<option value="05">05</option>
<option value="06">06</option>
<option value="07">07</option>
<option value="08">08</option>
<option value="09">09</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
</Form.Select>
</Col>
<Col>
<Form.Label style={{fontWeight: "bold"}}>Exp Year</Form.Label>
<Form.Select>
<option value="2022">2022</option>
<option value="2023">2023</option>
<option value="2024">2024</option>
<option value="2025">2025</option>
<option value="2026">2026</option>
<option value="2027">2027</option>
<option value="2028">2028</option>
<option value="2029">2029</option>
<option value="2030">2030</option>
<option value="2031">2031</option>
<option value="2032">2032</option>
</Form.Select>
</Col>
<Col>
<Form.Label style={{fontWeight: "bold"}}>CVC</Form.Label>
<Form.Control placeholder={"000"}/>
</Col>
</Row>
</div>
<br/><br/>
<div className="checkbox pcheck">
<label htmlFor="destinations-1">
<input type="checkbox" id="cash"/>
<b> Pay with with cash</b> <br/><br/>
<h3>By paying with cash I agree to advise my tour guide 30 minutes ahead of time
that I need to complete payment</h3>
</label>
</div>
</Col>
</Row>
</Form>
</Container>
<Footer/>
</>
);
};
export default Bookings;

React.JS Object passing during onclick event

I am new to react,
I am using card, when card "on click" i need to get the card object and place it in form dynamically,
(full code)
My code:
// reactstrap components
import {useState} from "react"
import {
Card,
CardHeader,
CardBody,
CardTitle,
Col,
Input,
FormGroup,
Form,
Container,
Row,
UncontrolledDropdown,
DropdownToggle,
DropdownItem,
DropdownMenu,
Button,
} from "reactstrap";
import Header from "components/Headers/Header.js";
import 'react-toastify/dist/ReactToastify.css';
import Navbar from "components/Navbars/modulenavbar"
import axios from "axios";
import React from "react";
import { Link } from "react-router-dom";
var apitoken= localStorage.getItem('apitoken');
const api=axios.create({baseURL:"https://api/v1/account"})
const options = {
headers: {'Authorization': apitoken}
}
const Accounts = () => {
const [accounts, setaccount] = React.useState([]);
const [loading, setLoading] = React.useState(true);
const [disabled, setDisabled] = useState(false);
React.useEffect(async () => {
const response = await api.get("/",options);
setaccount(response.data.response);
setLoading(false);
}, []);
if (loading) {
return <>Loading...</>;
}
function handleGameClick() {
setDisabled(!disabled);
}
This is were i get all my api value and append it
return (
<>
{accounts.map((student, index) => {
const { id, name, phone, email } = student //destructuring
return (
<>
<div style={{ width: "18rem" }} onClick={() => console.log(student)}>
I want to pass the object "Student" and use it in the default value of the forms shown below
<Card className="card-stats mb-4 mb-lg-1">
<CardBody>
<Row>
<div className="col">
<CardTitle className="h4 font-weight-bold mb-0">
{name}
</CardTitle>
<span className="h5">{phone}</span>
</div>
<div className="col">
<span className="h5">{email}</span>
</div>
</Row>
</CardBody>
</Card>
</div>
</>
)
})}
</>
)
}
Form Shows here
const Display = () => {
return (
<>
<Header />
<Container className="mt--7" fluid>
{/* Table */}
<Row>
<Col className="order-xl-1 " xl="2">
<CardHeader className="bg-white border-0">
<Row className="align-items-center">
<Col xs="8">
<Link to="/admin//accounts" className="ni ni-bold-left">
<span> View Account</span></Link>
</Col>
</Row>
</CardHeader>
<Card className="bg-secondary shadow navbar-nav-scroll">
<Accounts/>
</Card>
</Col>
<Col className="order-xl-1" xl="10">
<Card className="bg-secondary shadow">
<Navbar/>
<Row >
<Col className="shadow navbar-nav-scroll">
<Form>
<h6 className="heading-small text-muted mb-4">
Account Information
</h6>
<div className="pl-lg-4">
<Row>
<Col >
<FormGroup>
<label
className="form-control-label"
htmlFor="input-username"
>
Account Name
</label>
<Input
className="form-control-alternative"
id="input-username"
placeholder="Username"
type="text"
defaultValue={student.value}
/>
</FormGroup>
</Col>
</Row>
<Row>
<Col >
<FormGroup>
<label
className="form-control-label"
htmlFor="input-email"
>
Email address
</label>
<Input
className="form-control-alternative"
id="input-email"
placeholder="jesse#example.com"
type="email"
/>
</FormGroup>
</Col>
</Row>
<Row>
<Col >
<FormGroup>
<label
className="form-control-label"
htmlFor="input-email"
>
Phone
</label>
<Input
className="form-control-alternative"
id="input-phone"
placeholder="Phone"
type="text"
/>
</FormGroup>
</Col>
</Row>
</div>
</Form>
</Col>
<Col xs="9">
<Card className="card-stats mb-4 mb-lg-0">
<CardBody>
<div>
<Row className="align-items-center">
<Col xs="8">
</Col>
<Col className="text-right" xs="4">
<Button
color="success"
href="#pablo"
// onClick={save}
>
Save
</Button>
</Col>
</Row>
</div>
</CardBody>
</Card>
</Col>
</Row>
</Card>
</Col>
</Row>
</Container>
</>
);
};
export default Display;
Note:The above three sections of code is in the single component
I just want to dynamically append the values from object during "on click" event
Thanks in advance
You can store the clicked student value in state and pass it on to whichever component needs it as props
const Accounts = () => {
const [selectedStudent, setSelectedStudent] = useState({});
...
const handleStudentClick = (student) => {
setSelectedStudent(student)
}
return (
<>
{accounts.map((student, index) => {
const { id, name, phone, email } = student //destructuring
return (
<>
<div style={{ width: "18rem" }} onClick={() => handleStudentClick(student)}>
Now you can pass selected student as props to your child component

How do I resolve this error for a react-bootstrap-typeahead

I have a child component called ProductCard that takes props from the parent called CreateNewSales. The onChange function takes two argument and is defined in the parent. If I call that function in the ProductCard, I keep getting this error for the typeahead though every other input except the quantity input seems to be working just fine. Here are the code:
This is the ProductCard:
import React, { useState, Fragment } from 'react';
import { FormGroup, Label, Input, Col} from 'reactstrap';
import { Typeahead } from 'react-bootstrap-typeahead';
import PropTypes from 'prop-types';
import {PlusSquare, MinusSquare} from 'react-feather'
const plusSquare = <PlusSquare/>
const minusSquare = <MinusSquare/>
const ProductCard = (props) => {
console.log(props)
const ProductOptions = [{id:1,name: "Clothes"}, {id:2,name:"Services"}, {id:3,name:"Shows"}, {id:4,name: "Peace"}] //dummy date //res_data.payload.data.product
// const [singleSelections, setSingleSelections] = useState([]);
// from quantityIncrement.js
const [count, setCount] = useState(1)
const decrement = () => {
if(count === 1){
setCount(count)
} else{
setCount(count-1)
}
};
const increment = () => {
setCount(count+1)
};
return(
<Fragment>
<FormGroup>
<Label>Product Name</Label>
<Typeahead
id="basic-typeahead"
labelKey="name"
onChange={(e) => props.handleChange(e, props.index)}
// onInputChange={props.setProductName}
options={ProductOptions}
name={ProductOptions}
selected={props.value.productName}
style={{backgroundColor:"#d5deee"}}
value={props.value.productName}
/>
</FormGroup>
<FormGroup>
<div className="form-row">
<Col>
<Label for="quantity">Quantity</Label>
<div style={{display: "flex"}}>
<Input value={count} id="quantity" name="quantity" onChange={e=> setCount(e.target.value)} style={{backgroundColor: "#d5deee"}} />
<div style={{display:"flex", marginTop:"5px"}}><span><i style={{ width: 15, fontSize: 10, padding: 11, color: '#848b97' }} onClick={increment}>{plusSquare}</i></span><span><i style={{ width: 15, fontSize: 12, color: '#848b97' }} onClick={decrement}>{minusSquare}</i></span></div>
</div>
</Col>
<Col>
<Label for="discount">Discount</Label>
<Input type="text" id="discount" onChange = {(e) => props.handleChange(e, props.index)} value={props.value.discount} name="discount" style={{backgroundColor:"#d5deee"}} />
</Col>
</div>
</FormGroup>
<FormGroup>
<div className="form-row">
<Col>
<Label for="price">Price</Label>
<Input type="text" id="price" onChange={(e) => props.handleChange(e, props.index)} value={props.value.price} name="price" style={{backgroundColor:"#d5deee"}} />
</Col>
<Col>
<Label for="amountPaid">Amount Paid</Label>
<Input type="text" id="amountPaid" onChange={(e) => props.handleChange(e, props.index)} value={props.value.amountPaid} name="amountPaid" style={{backgroundColor:"#d5deee"}} />
</Col>
</div>
</FormGroup>
</Fragment>
)
}
ProductCard.propTypes = {
handleChange: PropTypes.func.isRequired,
value: PropTypes.object.isRequired,
// onClickQuantity: PropTypes.func.isRequired
}
export default ProductCard
This is the CreateNewSale:
import React, { Fragment, useState } from 'react';
import {Form, FormGroup, Label, Input, Card, Col, Row, CardBody, Button, ButtonGroup, Table} from 'reactstrap';
import {toast} from 'react-toastify';
import { Typeahead } from 'react-bootstrap-typeahead';
import { withRouter} from 'react-router';
// import {useHistory} from 'react-router-dom';
import {connect} from 'react-redux';
import {validateCreateNewSaleForm, responseErrorParser} from "../../components/authentication/validator"
// productCard.js
import ProductCard from '../../components/sales/ProductCard'
import {Trash2} from 'react-feather'
const trash2 = <Trash2/>
const CreateNewSale = (props) => {
const [, setIsCreatingNewSale] = useState(false)
// const [singleSelections, setSingleSelections] = useState([]);
// from the productCard.js
const [newProductValues, setNewProductValues] = useState([{
productName: [],
discount: "",
price: "",
amountPaid: "",
quantity: "1",
}]);
// const [newProductName, setNewProductName] = useState([{
// newProductNames: [],
// newCustomerName: []
// }])
// const handleInputChange = (event) => {
// setNewProductName({
// ...newProductName,
// [event.target.name]: event.target.value
// });
// }
const [customerName, setCustomerName] = useState([])
const [date, setDate] = useState('')
const [dueDate, setDueDate] = useState('')
const [vat, setVat] = useState('')
// const [visible, setVisible] = useState(false)
const handleChange = (event, index) => {
console.log( event )
const values = [...newProductValues];
values[index][event.target.name] = event.target.value
console.log('=======================>', values)
setNewProductValues(values);
// setNewProductValues({
// ...newProductValues,
// [event.target.name]: event.target.value
// });
}
const handleAddFields = (e) => {
setNewProductValues([...newProductValues, {discount:"", price: "",
amountPaid: "",
quantity: "1",
productName:[]
}])
}
const handleRemoveFields = (index) => {
const values = [...newProductValues];
values.splice(index, 1);
setNewProductValues(values);
}
const customerOptions = [{id: 1, name: "Olalekan"}, {id: 2, name:"Michael"}, {id: 3,name:"Emeka"}, {id:4,name: "Glory"}] //dummy data //res_data.payload.data.customer
const fields = {
customer_name: { default: '', message: 'Please enter an already created customer name' },
product_name: { default: '', message: 'Please enter an already created customer name' },
quantity: { default: '', message: 'Please select a quantity' },
discount: { default: '', message: 'Please enter the discount given' },
price: { default: '', message: 'Please select the price given' },
amount_paid: { default: '', message: 'Please enter the amount paid by the customer' },
date: { default: '', message: 'Please enter date' },
due_date: { default: '', message: 'Please enter due date given' },
vat: { default: '', message: 'Please enter the vat' },
}
const handleCreateNewSale = async (e) => {
e.preventDefault()
setIsCreatingNewSale(true);
const responsePayload = {
customer_name: newProductValues.newCustomerName, //customerName
product_name: newProductValues.newproductNames,
quantity: newProductValues.quantity,
discount: newProductValues.discount,
price: newProductValues.price,
amount_paid: newProductValues.amountPaid,
date: date,
due_date: dueDate,
vat: vat
}
const errors = validateCreateNewSaleForm(responsePayload, fields)
if (errors.isErrors) {
setIsCreatingNewSale(false)
setTimeout(() => {
errors.errors.forEach(e => toast.error(e.message))
}, 400);
} else {
const response = await props.CreateNewSale(responsePayload)
if (response.status) {
const newSale = response.payload.data.id
localStorage.setItem('__grm__act__biz__', newSale.toString())
// props.history.push(`/business/${newSale}.toString/sales/invoice`, {previousLocation: props.location.pathname})
} else {
setIsCreatingNewSale(false)
const payload = response.payload
const errs = responseErrorParser(payload.data)
setTimeout(() => {
errs.forEach(e => toast.error(e.message))
}, 400);
}
}
}
return(
<Fragment>
<div style={{display:"flex", fontFamily:"'Poppins', sans-serif"}}>
<div className="col-lg-10" style={{margin: "0 auto", maxWidth:"500px", width:"100%"}}>
<Form>
<Card>
<CardBody>
<FormGroup>
<Label>Customer Name</Label>
<Typeahead
id="basic-typeahead"
labelKey="name"
onChange={setCustomerName}
options={customerOptions}
selected={customerName}
value={customerName}
name="customerName"
style={{backgroundColor:"#d5deee"}}
/>
</FormGroup>
</CardBody>
</Card>
{ newProductValues.map((newProductValue, index) => (
<div key={index}>
<Card >
<CardBody>
<Col style={{textAlign: "right"}}>
<i onClick={() => handleRemoveFields()} >{trash2}</i>
</Col>
<ProductCard index={index} handleChange={handleChange} value={newProductValue} />
</CardBody>
</Card>
</div>
))}
<Row>
<Col>
<p onClick={() => handleAddFields()} style={{marginLeft:"20px"}}> <span style={{fontSize:"18px"}}>+</span> Add another product</p>
</Col>
</Row>
<Row>
<Col>
<p onClick={() => handleAddFields()} style={{marginLeft:"20px"}}> <span style={{fontSize:"18px"}}>+</span> Add another product</p>
</Col>
</Row>
<Card>
<CardBody>
<FormGroup>
<div className="form-row">
<Col>
<Label for="date">Date</Label>
<Input className="form-control digits" type="date" defaultValue="2018-01-01" value={date} onChange={e => setDate(e.target.value)} id="date" name="date" style={{backgroundColor:"#d5deee"}} />
</Col>
<Col>
<Label for="dueDate">Due Date</Label>
<Input className="form-control digits" type="date" defaultValue="2018-01-01" value={dueDate} onChange={e => setDueDate(e.target.value)} id="dueDate" name="dueDate" style={{backgroundColor:"#d5deee"}} />
</Col>
</div>
</FormGroup>
<FormGroup>
<div className="form-row">
<Col>
<Label for="vat">VAT %</Label>
<Input type="text" id="vat" value={vat} onChange={e => setVat(e.target.value)} style={{backgroundColor:"#d5deee"}} />
</Col>
</div>
</FormGroup>
<div style={{margin:"0 auto", textAlign:"center"}}>
<p style={{fontSize:"12px"}}>Only click cleared if this sales have been paid in full</p>
<Row>
<Col>
<ButtonGroup>
<Button outline color="primary" type="button">Cleared</Button>
<Button outline color="primary" type="button">Not Cleared</Button>
</ButtonGroup>
</Col>
</Row>
</div>
<Row className="m-t-50">
<Col lg={`6`}>
<Button outline color="primary" size="lg" style={{maxWidth:"200px", width:"100%"}}>SAVE</Button>
</Col>
<Col lg={`6`}>
<Button color="primary" size="lg" onClick={e => handleCreateNewSale(e)} style={{maxWidth:"200px", width:"100%"}}>CREATE</Button>
</Col>
</Row>
</CardBody>
</Card>
</Form>
</div>
<div className="col-lg-2" style={{backgroundColor:"#eaf6fd", position:"fixed", right:0, height:"100%",}}>
<Card className="m-t-50">
<CardBody>
<div>You have added <span>0</span> products</div>
</CardBody>
</Card>
<div className="table-responsive">
<Table borderless>
<tbody>
<tr>
<td className="bd-t-none">Sub Total</td>
<td>000 000 000</td>
</tr>
<tr style={{fontWeight:"bold"}}>
<td className="bd-t-none">Total</td>
<td>000 000 000</td>
</tr>
</tbody>
</Table>
</div>
</div>
</div>
</Fragment>
)
}
const mapStateToProps = (state) => ({
requestingCreateNewSale: state.isRequestingCreateNewSale,
});
const actions = {
CreateNewSale: CreateNewSale
};
export default connect(mapStateToProps, actions)(withRouter(CreateNewSale))
And this is the error I keep getting everytime I want to change the value for the productName typeahead:
TypeError: Cannot read property 'name' of undefined
handleChange
src/pages/sales/CreateNewSales.js:54
51 | const handleChange = (event, index) => {
52 | console.log( event )
53 | const values = [...newProductValues];
> 54 | values[index][event.target.name] = event.target.value
| ^ 55 | console.log('=======================>', values)
56 | setNewProductValues(values);
57 | // setNewProductValues({
View compiled
onChange
src/components/sales/ProductCard.jsx:40
37 | <Typeahead
38 | id="basic-typeahead"
39 | labelKey="name"
> 40 | onChange={(e) => props.handleChange(e, props.index)}
| ^ 41 | // onInputChange={props.setProductName}
42 | options={ProductOptions}
43 | name={ProductOptions}

React change variable onChange-method

I am experimenting with React and I have the following problem. Different employees are listed in the "medewerker:" dropdown. When 1 is selected, the data is replaced by the value of the selection using the 'handelChangeEmployee' function in the 'employeeOrder' variable. In the console.log everything changes as expected. Only if I read variable: 'employeeOrder' will it continue to show the previously set value. and this is not being replaced, is this possible? and if so how?
So what I want to achieve is that when a selection is made, the value in the existing variable is replaced with the value of the selection.
The code that I am currently using is:
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import styles from "assets/jss/material-dashboard-react/views/dashboardStyle.js";
import { Container } from "react-bootstrap";
import { Row } from "react-bootstrap";
import { Col } from "react-bootstrap";
import Close from '#material-ui/icons/Close';
import { render } from "react-dom";
const useStyles = makeStyles(styles);
export default function ChaskDesk() {
const employee = ["Robin","Raoul","Joppe "];
const service = ["Knippen","Scheren","Wassen"];
const counting = [1,2,3,4,5,6];
const gender = ["man", "vrouw", "kind"];
const client = ["Passant"];
let employeeOrder = 'Raoul';
const serviceOrder = [];
const countingOrder = [];
const genderOrder = [];
const clientOrder = "";
const payment = 0;
const classes = useStyles();
const handelChangeGender = function(event){
genderOrder.push(event.target.value);
console.log(genderOrder);
};
const handelChangeService = function(event){
serviceOrder.push(event.target.value);
console.log(serviceOrder);
};
let handelChangeEmployee = function(event){
console.log(employeeOrder);
employeeOrder = event.target.value;
console.log(employeeOrder);
};
return (
<div>
<Container className={classes.containerPixelActive}>
<h3>Afrekenen</h3>
<Row className={classes.tablePixelRow}>
<Col md={8} className={classes.rowChashdesk}>
<form>
<Row>
<Col md={6}>
<label>
Klant:
</label>
<br/>
<select >
{
client.map(function(item, i){
return <option key={i} value={item}>{item}</option>
})
}
</select>
</Col>
</Row>
<Row>
<Col md={6}>
<div className={classes.rowOfForm}>
<label>
Gender:
</label>
<br/>
<select onChange={handelChangeGender}>
{
gender.map(function(item, i){
return <option key={i} value={item}>{item}</option>
})
}
</select>
</div>
</Col>
</Row>
<Row>
<Col md={6}>
<div className={classes.rowOfForm}>
<label>
Behandeling:
</label>
<br/>
<select onChange={handelChangeService}>
{
service.map(function(item, i){
return <option key={i} value={item}>{item}</option>
})
}
</select>
</div>
</Col>
<Col md={6}>
<div className={classes.rowOfForm}>
<label>
Medewerker:
</label>
<br/>
<select onChange={handelChangeEmployee}>
{
employee.map(function(item, i){
return <option key={i} value={item}>{item}</option>
})
}
</select>
</div>
</Col>
</Row>
<Row>
<Col md={6}>
<div className={classes.rowOfForm}>
<label>
Verkregen behandeling:
</label>
<br/>
<input type="text" name="name" />
</div>
</Col>
<Col md={2}>
<div className={classes.rowOfForm}>
<label>
Aantal:
</label>
<br/>
<select>
{
counting.map(function(item, i){
return <option key={i} value={item}>{item}</option>
})
}
</select>
</div>
</Col>
<Col md={2}>
<div className={classes.rowOfForm}>
<label>
Prijs:
</label>
<br/>
<input type="text" name="name"/>
</div>
</Col>
<Col md={2}>
<div className={classes.rowIcon}>
<Close size={20} ></Close>
</div>
</Col>
</Row>
</form>
</Col>
<Col md={3} className={classes.rowChashdesk}>
<h5>Totaal overzicht</h5>
<h6>Medewerker</h6>
<p>{employeeOrder}</p>
<h6>Behandeling</h6>
<p>{serviceOrder}</p>
<h6>Aantal</h6>
<p>{countingOrder}</p>
<h6>Klant</h6>
<p>{clientOrder}</p>
<h6>Te betalen</h6>
<p>{payment}</p>
</Col>
</Row>
</Container>
</div>
);
}
The only way a react component knows to rerender is by your component (or some component above it) settings state. You're not using state, so it doesn't rerender.
Change this:
let employeeOrder = 'Raoul';
To this:
import { useState } from 'react';
// ... code omitted
const [employeeOrder, setEmployeeOrder] = useState('Raoul')
And change your handler to:
const handelChangeEmployee = function(event) {
setEmployeeOrder(event.target.value)
}
You will need to do similar things for genderOrder and ServiceOrder. You can't just push into an array and expect the page to update, you need to set state to a new array to cause the component to rerender. Don't mutate the old array, create a new one, as in:
setGenderOrder([...genderOrder, event.target.value])
For more info on useState and other hooks, see this page

React useState hook does not shows correct state of array

I have two functional components and from parent component I am creating set of controls dynamically. Based on each item created I want to delete them but every time last one is getting deleted. For example three rows created when I delete second or first on,last one was getting deleted.
Education.jsx
function Education(props) {
const blankEdu = { id: 0, name: "", percentage: "", year: "" };
const [eduState, setEduState] = useState([{ ...blankEdu }]);
const addEducation = () => {
setEduState([...eduState, { ...blankEdu }]);
};
function handleRemove(index) {
console.log(index);
if (eduState.length != 1) {
const updatedEdu = [...eduState];
updatedEdu.splice(index, 1);
setEduState([...updatedEdu]);
}
}
const handleEducationChange = (index, e, c) => {
const updatedEdu = [...eduState];
updatedEdu[index][c] = e.target.value;
updatedEdu[index]["id"] = index;
setEduState(updatedEdu);
};
return (
<div>
<div className="shadow p-3 mb-5 bg-white rounded">
Final Step: Education
</div>
{eduState.map((val, idx) => (
<div
key={idx}
>
<EducationInput
key={`edu-${idx}`}
idx={idx}
handleEducationChange={handleEducationChange}
/>
{eduState.length > 1 ? (
<Button variant="danger" onClick={() => handleRemove(idx)}>
Remove Course
</Button>
) : null}
</div>
))}
<Button variant="outline-info" onClick={addEducation}>
Add New Degree
</Button>
</div>
);
}
export default Education;
EducationInput.jsx
const EducationInput = ({ idx, handleEducationChange }) => {
return (
<div key={`edu-${idx}`} id={`edu-${idx}`}>
<span className="border border-success">
<Form>
<Form.Group as={Row}>
<Form.Label column sm={3}>
{`Course #${idx + 1}`}:
</Form.Label>
<Col sm={5}>
<input
type="text"
onChange={e => handleEducationChange(idx, e, "name")}
/>
</Col>
</Form.Group>
<Form.Group as={Row}>
<Form.Label column sm={3}>
Passing Year:
</Form.Label>
<Col sm={5}>
<input
type="text"
onChange={e => handleEducationChange(idx, e, "year")}
/>
</Col>
</Form.Group>
</Form>
</span>
</div>
);
};
export default EducationInput;
I checked and verified value of updatedEdu by printing on console. It is giving correct output on console but setEduState function does not updating properly on UI, don't know why.
You are depending the index of the item, but indexes are changing when you add or remove elements, so they are not reliable.
You need to generate an automatic unique id when creating a new education.
For example uuid package is popular for this task.
I refactored your code a little bit to make it work:
Education:
import React, { useState } from "react";
import EducationInput from "./EducationInput";
import Button from "react-bootstrap/Button";
import uuidv4 from "uuid/v4";
function Education(props) {
const blankEdu = { id: "", name: "", percentage: "", year: "" };
const [eduState, setEduState] = useState([{ ...blankEdu }]);
const addEducation = () => {
setEduState([...eduState, { ...blankEdu, id: uuidv4() }]);
};
function handleRemove(id) {
console.log(id);
if (eduState.length > 1) {
const updatedEdus = eduState.filter(edu => edu.id !== id);
setEduState(updatedEdus);
}
}
const handleEducationChange = (id, field, value) => {
console.log(field, value);
let updatedEducations = eduState.map(edu => {
if (edu.id === id) return edu;
edu[field] = value;
return edu;
});
setEduState(updatedEducations);
};
return (
<div>
<div className="shadow p-3 mb-5 bg-white rounded">
Final Step: Education
</div>
{eduState.map(val => (
<div key={val.id}>
<EducationInput
key={`edu-${val.id}`}
idx={val.id}
handleEducationChange={handleEducationChange}
/>
{eduState.length > 1 ? (
<Button variant="danger" onClick={() => handleRemove(val.id)}>
Remove Course
</Button>
) : null}
</div>
))}
<Button variant="outline-info" onClick={addEducation}>
Add New Degree
</Button>
<br />
<br />
Educations in json:{JSON.stringify(eduState)}
</div>
);
}
export default Education;
EducationInput
import React from "react";
import Form from "react-bootstrap/Form";
import Col from "react-bootstrap/Col";
import Row from "react-bootstrap/Row";
const EducationInput = ({ idx, handleEducationChange }) => {
return (
<div key={`edu-${idx}`} id={`edu-${idx}`}>
<span className="border border-success">
<Form>
<Form.Group as={Row}>
<Form.Label column sm={3}>
{`Course #${idx + 1}`}:
</Form.Label>
<Col sm={5}>
<input
type="text"
name="name"
onChange={e =>
handleEducationChange(idx, e.target.name, e.target.value)
}
/>
</Col>
</Form.Group>
<Form.Group as={Row}>
<Form.Label column sm={3}>
Passing Year:
</Form.Label>
<Col sm={5}>
<input
type="text"
name="year"
onChange={e =>
handleEducationChange(idx, e.target.name, e.target.value)
}
/>
</Col>
</Form.Group>
</Form>
</span>
</div>
);
};
export default EducationInput;
Codesandbox

Resources