Dynamically Calculating values in React JS Form using Hooks - reactjs

I am working on PG finder application and I want that on the owner side on adding the shared number he/she automatically gets the total capacity of the rooms (i.e like we have 2 sharing and total no of rooms available are 3 so total capacity/ beds will be 6)
So I want that column to generate value dynamically
Image Reference for query
As you can see the totalcapacity value is getting copied for the next dynamic generated form field also. I want them to be separate.
import React, { useEffect, useState } from "react";
import './roominfo.css';
import { ImBin } from 'react-icons/im';
const RoomInfo = () => {
let handleChange = (i, e) => {
let newFormValues = [...formValues]; /** makes a copy of the current form values and assign it to newFormValues **/
newFormValues[i][e.target.name] = e.target.value;
setFormValues(newFormValues);
}
let addFormFields = () => {
setFormValues([...formValues, { shared_no: "", no_of_rooms: "", rent_per_month: "", vacancy: "",total_capacity: 0}])
};
let removeFormFields = (i) => {
let newFormValues = [...formValues];
newFormValues.splice(i, 1);
setFormValues(newFormValues)
}
const [formValues, setFormValues] = useState([{ shared_no: "", no_of_rooms: "", rent_per_month: "", total_capacity: "", vacancy: "" }])
const [total_no_of_rooms, settotal_no_of_rooms] = useState('1');
const [rooms_entered, setrooms_entered] = useState('');
const getTotalCapacity = () => {
return formValues.reduce((total,element) => {
return total + Number(element.shared_no) * Number(element.no_of_rooms);
}, 0);
};
const Total_no_of_rooms_entered = () => {
return formValues.reduce((total, element) => {
return total + Number(element.no_of_rooms);
}, 0);
};
useEffect(() => {
if (rooms_entered > total_no_of_rooms) {
window.alert("No more rooms can be added");
}
},)
return (
<>
<div className='heading'>
<h1 style={{ marginBottom: '50px' }}>Enter Your PG Room Details</h1>
</div>
<form>
<div className="form-inline" style={{ marginBottom: '50px' }}>
<label>Total of Rooms: </label>
<input type="number" name="total_no_of_rooms" style={{ width: '90px' }} onClick={(e) => settotal_no_of_rooms(e.target.value)} defaultValue={1} />
<label>Rooms Entered:</label>
<div><input type="number" name="rooms_entered" value={Total_no_of_rooms_entered()} onClick={(e) => setrooms_entered(e.target.value)} readOnly></input></div>
</div>
</form>
<div>
<form>
{formValues.map((element, index) => (
<div className="form-inline" key={index} style={{ borderBottom: '1px solid black' }}>
<label>Sharing Number</label>
<select id="shared_no" name="shared_no" title="no of shared rooms" value={element.shared_no || ""} onChange={e => handleChange(index, e)} >
<option value="">---Select---</option>
<option value="1">Single Sharing</option>
<option value="2">Two Bed Sharing</option>
<option value="3">Three Bed Sharing</option>
<option value="4">Four Bed Sharing</option>
<option value="5">Five Bed Sharing</option>
</select>
<label> No of Rooms:</label>
<input type="number" name="no_of_rooms" value={element.no_of_rooms || ""} onChange={e => handleChange(index, e)}></input>
<label> Rent per month:</label>
<input type="number" style={{ width: '100px' }} name="rent_per_month" value={element.rent_per_month || ""} onChange={e => handleChange(index, e)}></input>
<label> Total Capacity:</label>
<input type="number" style={{ width: '50px' }} name="total_capacity" value={getTotalCapacity()} onChange={e => handleChange(index, e)}></input>
<label> Vacancy:</label>
<input type="number" style={{ width: '50px' }} name="vacancy" value={element.vacancy || ""} onChange={e => handleChange(index, e)}></input>
{
index ?
<button type="button" className="button remove" onClick={() => removeFormFields(index)}><ImBin /></button>
: null
}
</div>
))}
<div className="button-section">
<button className="button add" type="button" onClick={() => addFormFields()}>Add</button>
<button className="button submit" type="submit">Submit</button>
</div>
</form>
</div>
</>
)
}
export default RoomInfo
This is the code. Can you please help me with how to solve it.Thank you

Related

Submitting dynamically created form to database in reactJS

I am trying to insert the values through this dynamic form but I am only able to insert just one entry (even though I enter multiple forms) and the values that are getting inserted are 0 (in the database as well).
I am passing the index still I am not getting the desired output. The list looks like this:
List of the entered details
The previous entry was entered manually.
This is the CODE through which I submit values.
import React, { useEffect, useState } from "react";
import './roominfo.css';
import { ImBin } from 'react-icons/im';
import { useNavigate, useParams } from 'react-router-dom'
import RoomInfoService from '../services/RoomInfoService';
const RoomInfo = () => {
const [shared_no] = useState();
const [no_of_rooms] = useState();
const [rent_per_month] = useState();
const [vacancy] = useState();
const [total_capacity] = useState();
const [pg_fid, setpgfid] = useState();H
let handleChange = (i, e) => {
let newFormValues = [...formValues]; /** makes a copy of the current form values and assign it to newFormValues **/
newFormValues[i][e.target.name] = e.target.value;
setFormValues(newFormValues);
}
const navigate = useNavigate();
let addFormFields = () => {
setFormValues([...formValues, { shared_no: "", no_of_rooms: "", rent_per_month: "", vacancy: "",total_capacity: ""}])
};
let removeFormFields = (i) => {
let newFormValues = [...formValues];
newFormValues.splice(i, 1);
setFormValues(newFormValues)
}
const [formValues, setFormValues] = useState([{ shared_no: "", no_of_rooms: "", rent_per_month: "", total_capacity: "", vacancy: "" }])
/*const [settotal_no_of_rooms] = useState('1');
const [setrooms_entered] = useState('1');
const getTotalCapacity = () => {
return formValues.reduce((total,element) => {
return total + Number(element.shared_no) * Number(element.no_of_rooms);
}, 0);
};*/
const resetForm = () => setFormValues([{shared_no: "", no_of_rooms: "", rent_per_month: "", vacancy: "",total_capacity: ""}]);
const Total_no_of_rooms_entered = () => {
return formValues.reduce((total, element) => {
return total + Number(element.no_of_rooms);
}, 0);
};
const saveRoomInfo = (e) =>{
e.preventDefault();
const roominfo = [...formValues];
RoomInfoService.createRoomInfo(roominfo).then((response) => {
console.log(response.data);
navigate('/listroominfo');
}).catch(error =>{
console.log(error);
})
}
return (
<>
<div className='heading'>
<h1 style={{ marginBottom: '50px' }}>Enter Your PG Room Details</h1>
</div>
<form>
<div className="form-inline" style={{ marginBottom: '50px' }}>
{/*<label>Total of Rooms: </label>
<input type="number" name="total_no_of_rooms" style={{ width: '90px' }} onClick={(e) => settotal_no_of_rooms(e.target.value)} defaultValue={1} /> */}
<label>Rooms Entered:</label>
<div><input type="number" name="rooms_entered" value={Total_no_of_rooms_entered()} readOnly></input></div>
</div>
</form>
<div>
<form>
{formValues.map((element, index) => (
<div className="form-inline" key={index} style={{ borderBottom: '1px solid black' }}>
<label>Sharing Number</label>
<select id="shared_no" name="shared_no" title="no of shared rooms" value={element.shared_no || ""} onChange={e => handleChange(index, e)} >
<option value="">---Select---</option>
<option value="1">Single Sharing</option>
<option value="2">Two Bed Sharing</option>
<option value="3">Three Bed Sharing</option>
<option value="4">Four Bed Sharing</option>
<option value="5">Five Bed Sharing</option>
</select>
<label> No of Rooms:</label>
<input type="number" style={{ width: '60px' }} name="no_of_rooms" value={element.no_of_rooms || ""} onChange={e => handleChange(index, e)}></input>
<label> Rent per month:</label>
<input type="number" style={{ width: '100px' }} name="rent_per_month" value={element.rent_per_month || ""} onChange={e => handleChange(index, e)}></input>
<label> Total Capacity:</label>
<input type="number" style={{ width: '80px' }} name="total_capacity" value={element.total_capacity} onChange={e => handleChange(index, e)}></input>
<label> Vacancy:</label>
<input type="number" style={{ width: '50px' }} name="vacancy" value={element.vacancy || ""} onChange={e => handleChange(index, e)}></input>
{
index ?
<button type="button" className="button-remove" onClick={() => removeFormFields(index)}><ImBin size={20}/></button>
: null
}
</div>
))}
<div className="button-section">
<button className="button" type="button" onClick={() => addFormFields()}>Add</button>
<button className="button" type="button" onClick={resetForm}>Reset</button>
<button className="button" type="submit" onClick={(e) => saveRoomInfo(e)}>Submit</button>
</div>
</form>
</div>
</>
)
}
export default RoomInfo
Reference of Dynamic Form
The issue is while I am fetching the data from the form. But I can't figure it out. Thank you.

Im facing error in firstname ,lastname required in my code. It is not showing those errors

Here for email, password and confirm password error messages are showing but for firstname, phone number and lastname the error is not showing. How can I find out what that error is?
For email when I click on that field and do not give any value, it is showing an error and the same thing for firstname.
import React from "react";
import { useState } from "react";
const emailValidator = /^(([^<>()\[\]\\.,;:\s#"]+(\.[^<>()\[\]\\.,;:\s#"]+)*)|(".+"))#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
function Register(props) {
const [state, setState] = useState({
email: "",
emailAddressError: "",
firstName: "",
firstNameError: ""
});
const handleChange = (event) => {
const { name, value } = event.target;
setState((prev) => ({ ...prev, [name]: value }));
return;
};
const handleBlur = (event) => {
const { name } = event.target;
validateField(name);
return;
};
const handleSubmit = (e) => {
e.preventDefault();
let formFileds = ["email", "firstName"];
let isValid = true;
formFileds.forEach((field) => {
isValid = validateField(field) && isValid;
});
if (isValid) setState((prev) => ({ ...prev, isFormSubmitted: true }));
else setState((prev) => ({ ...prev, isFormSubmitted: false }));
return state.isFormSubmitted;
};
const validateField = (name) => {
let isValid = false;
if (name === "email") isValid = validateemail();
else if (name === "firstName") isValid = validatefirstName();
return isValid;
};
const validatefirstName = () => {
let firstNameError = "";
const value = state.firstName;
if (value.trim() === "") firstNameError = "First Name is required";
setState((prev) => ({ ...prev, firstNameError }));
return firstNameError === "";
};
const validateemail = () => {
let emailAddressError = "";
const value = state.email;
if (value === "") emailAddressError = "Email Address is required";
else if (!emailValidator.test(value))
emailAddressError = "Email is not valid";
setState((prev) => ({ ...prev, emailAddressError }));
return emailAddressError === "";
};
return (
<div id="__next">
<div class="no-gutters row" style={{ height: "100vh" }}>
<div class="d-flex flex-column justify-content-center align-items-center h-100 col-12 col-md-6">
<div class="container">
<div class="d-flex justify-content-center row">
<div class="col-auto col-lg-8">
<h5 class="fw-bold mb-5">Sign Up</h5>
<form class="w-100">
<div class="d-flex form-group">
<div class="flex-fill mr-5">
<span style={{ color: "red" }}> *</span>
<label for="exampleEmail" class="fw-bold">
First Name
</label>
<input
name="firstName"
value={state.firstName}
onChange={handleChange}
maxLength="20"
class="form-control"
placeholder="First Name"
/>
</div>
{state.firstNameError && (
<div className="errorMsg" style={{ color: "red" }}>
{state.firstNameError}
</div>
)}
</div>
<div class="form-group">
<span style={{ color: "red" }}> *</span>
<label for="exampleEmail" class="fw-bold">
Email
</label>
<input
name="email"
class="form-control"
value={state.email}
onChange={handleChange}
placeholder="Email"
onBlur={handleBlur}
autoComplete="off"
/>
</div>
{state.emailAddressError && (
<div className="errorMsg" style={{ color: "red" }}>
{state.emailAddressError}
</div>
)}
<div class="d-flex justify-content-between align-items-center mt-5">
<a
href="/login"
style={{ textDecoration: "none", color: "#bd744c" }}
>
{" "}
</a>
<button
class="btn "
style={{ backgroundColor: "#bd744c", color: "white" }}
onSubmit={handleSubmit}
>
<b>SIGN UP</b>
</button>
</div>
</form>
<br />
</div>
</div>
</div>
</div>
<div class="d-none d-md-inline-block h-100 Register_backgroundImage__2j-eI col-sm-6"></div>
</div>
</div>
);
}
// export default Register;
export default Register;
You forgot to call onBlur={handleBlur} in firstName and I have made small changes in your code:
Now it will show errors when you click on submit.

stacked dynamic inputs - reactjs

I have an input and a select starting when placing any value in the case of the input, it begins to generate dynamic statements and in the case of the input, dynamic inputs are generated but in decrement, everything works fine, I only need that the dynamic inputs that begin to appear are show one by one and not all piled up as I show in the picture.
problem image
how do i want it to be
import React, { useState } from "react";
//input dynamic
import Row from "./Row2";
let initialState = {
first: null,
arraySelect: []
};
function Pruebas(props) {
/*input dynamic */
const [rows, setRows] = useState([]);
const [initialeRow, setInitialRow] = useState({ nombre: "" });
const handleOnChange = (index, value) => {
const copy = rows.map((e, i) => {
if (i === index) {
e.nombre = value;
}
return e;
});
setRows([...copy]);
};
const handleOnAdd = () => {
if (initialeRow.nombre >= 1) {
setInitialRow({ nombre: initialeRow.nombre - 1 });
setRows([...rows, initialeRow]);
}
};
/////////////////////////////////////////////////////
const [input_multi, setInput_multi] = useState();
const [arraySelect, setarraySelect] = useState(initialState.arraySelect);
const [numberIni, setnumberIni] = useState(initialState.first);
const getArray = (value) => {
let arr = [];
{
let reco = Math.round(numberIni - parseInt(value));
console.log(reco);
if (parseInt(value) == numberIni) {
return false;
}
Array(reco)
.fill(1)
.map((value2, key) => {
arr.push(parseInt(value) + parseInt(key + 1));
});
}
return arr;
};
const setSelect = (value) => {
let isArray = getArray(value);
if (isArray) {
setarraySelect([...arraySelect, isArray]);
}
//input dynamyc
if (initialeRow.nombre >= 1) {
setInitialRow({ nombre: initialeRow.nombre - 1 });
setRows([...rows, initialeRow]);
}
};
//input dynamic
const handleInput_division = (event) => {
setInitialRow({ nombre: event.target.value });
};
const handleSubmit = (event) => {
event.preventDefault();
setnumberIni(event.target.numberIni.value);
};
const resetForm = () => {
setnumberIni(null);
setarraySelect([]);
};
return (
<div>
<form onSubmit={handleSubmit}>
<div class="row">
<label>PHASES</label>
<div class="col-sm-6">
<h6>enter a number</h6>
<div class="input-group ">
<input
type="number"
name="numberIni"
placeholder="0"
class="form-control"
value={input_multi}
onChange={(event) => setInput_multi(event.target.value)}
/>
<br />
<button type="submit" className="btn btn-success"> <i class="far fa-save"></i></button>
<br />
<div class="col-sm-6">
<h6>2 - # input dynamic</h6>
<div class="input-group ">
<select name='numberIni2' class='form-control' onChange={handleInput_division}>
<option value='no' selected>
Seleccione </option>
<option value='2'> 2</option>
<option value='3'>3
</option>
</select>
<br/>
</div>
</div>
</div>
</div>
</div>
</form>
<br />
<div class="col-sm-12 btn btn-primary">
<b>PHASES</b>
</div>
<br /> <br />
<div class="row">
<div class="col-sm-12">
{numberIni && (
<div class="col-sm-12">
<label>
<font size="2">
1° PHASES <br />
select a number : {" "}
</font>
</label>
<select onChange={(e) => setSelect(e.target.value)} name="" id="">
<option value="seleccione">Seleccione</option>
{Array(parseInt(numberIni))
.fill(1)
.map((value, key) => {
return <option value={key + 1}>{key + 1} equipment</option>;
})}
</select>
<label>
<font size="2"> equipment </font>{" "}
</label>
{Array(parseInt(numberIni))
.fill(1)
.map((value, key2) => {
return (
<div>
{arraySelect[key2] && (
<>
<label>
<font size="2">
2° select another number <br />
classify: {" "}
</font>{" "}
</label>
<select
onChange={(e) => setSelect(e.target.value)}
name=""
id=""
>
<option value="seleccione">Seleccione</option>
{arraySelect[key2].map((value, key3) => {
return (
<option value={arraySelect[key2][key3]}>
{arraySelect[key2][key3]} equipment
</option>
);
})}
</select>
{rows.map((e, index) => (
<Row
nombre={e.nombre}
index={index}
onChange={(index, value) => handleOnChange(index, value)}
key={index}
/>
))}
</>
)}
</div>
);
})}
</div>
)}
</div>
</div>
{numberIni && (
<input
onClick={() => resetForm()}
type="button"
className="btn btn-danger"
value="restart phase"
/>
)}
</div>
);
}
export default Pruebas;
//Row2
const Row = (props) => {
const { onChange, onRemove, nombre, index } = props;
console.log(props);
return (
<div>
<input
disabled
value={nombre}
onChange={(e) => onChange(index, e.target.value)}
placeholder="Decrementar"
/>
</div>
);
};
export default Row;

How do I change the state between inputs?

I am trying to make an application that calculates tax and discounts, but I could not figure out how to establish communication between states. Since the change between inputs will be continuous, I gave the onkeyup event for each inbox. Every time this event is called, the called function must do the necessary actions. For example, when I enter the quantity and unitPrice values, it will multiply the two values and assign them to the goodsServiceAmt value. The application also has the ability to add and delete rows. The calculations of each line should be in itself. I tried to do it with the handleQuantity function, the state is updating but the value in the input does not change.
const App = () => {
const [mainData, setMainData] = useState([
{
id: 1,
quantity: "",
unitPrice: "",
discRate: "",
discAmt: "",
kdvAmt: "",
kdvRate: "",
goodsServiceAmt: "",
},
]);
const deleteRow = (e, i) => {
e.preventDefault();
const newArr = [...mainData];
console.log(i);
newArr.splice(i, 1);
setMainData(newArr);
};
const handleChangeInput = (e, i) => {
const values = [...mainData];
values[i][e.target.name] = e.target.value;
setMainData(values);
};
const addRow = () => {
const id = mainData.length ? mainData.length + 1 : 0;
console.log(id);
setMainData([
...mainData,
{
id,
quantity: "",
unitPrice: "",
discRate: "",
discAmt: "",
kdvAmt: "",
kdvRate: "",
goodsServiceAmt: "",
},
]);
};
const handleQuantity = (e, i) => {
const deger = [...mainData];
deger[i].unitPrice = e.target.value;
setMainData(deger);
};
return (
<div style={{ display: "flex", flexDirection: "column" }}>
{mainData.map((v, i) => (
<form key={i} style={{ display: "flex" }}>
<span style={{ width: "50px", height: "50px" }}>{v.id}</span>
<div className="input-cont">
<label htmlFor="quantity">quantity</label>
<input
type="text"
name="quantity"
value={mainData.quantity}
onChange={(e) => handleChangeInput(e, i)}
onKeyUp={(e) => handleQuantity(e, i)}
/>
</div>
<div className="input-cont">
<label htmlFor="unitPrice">unitPrice</label>
<input
type="text"
name="unitPrice"
value={mainData.unitPrice}
onChange={(e) => handleChangeInput(e, i)}
/>
</div>
<div className="input-cont">
<label htmlFor="discRate">discRate</label>
<input
type="text"
name="discRate"
value={mainData.discRate}
onChange={(e) => handleChangeInput(e, i)}
/>
</div>
<div className="input-cont">
<label htmlFor="discAmt">discAmt</label>
<input
type="text"
name="discAmt"
value={mainData.discAmt}
onChange={(e) => handleChangeInput(e, i)}
/>
</div>
<div className="input-cont">
<label htmlFor="kdvRate">kdvRate</label>
<input
type="text"
name="kdvRate"
value={mainData.kdvRate}
onChange={(e) => handleChangeInput(e, i)}
/>
</div>
<div className="input-cont">
<label htmlFor="kdvAmt">kdvAmt</label>
<input
type="text"
name="kdvAmt"
value={mainData.kdvAmt}
onChange={(e) => handleChangeInput(e, i)}
/>
</div>
<div className="input-cont">
<label htmlFor="goodsServiceAmt">goodsServiceAmt</label>
<input
type="text"
name="goodsServiceAmt"
value={mainData.goodsServiceAmt}
onChange={(e) => handleChangeInput(e, i)}
/>
</div>
<button onClick={(e) => deleteRow(e, i)}>delete</button>
</form>
))}
<button onClick={addRow}>add row</button>
<button onClick={() => console.log(mainData)}>clg</button>
</div>
);
};
export default App;
That happens because you're accessing the data in your inputs like an object but in your useState it's an array.
Change your use state to:
const [mainData, setMainData] = useState({
id: 1,
quantity: "",
unitPrice: "",
discRate: "",
discAmt: "",
kdvAmt: "",
kdvRate: "",
goodsServiceAmt: "",
});
Or change the value in your inputs to:
value={mainData[0].quantity}
Since your mainData is an array, when you are doing this assign to the input value mainData.quantity, you are actually passing an undefined, converting the input to an uncontrolled input. That uncontrolled input makes it look like you are getting the data from the state, but actually it isn't. So you need to change those calls to mainData[i].quantity to get the data properly.
And as a note, you can still use the onChange function to handle the quantity

Encountered two children with the same key, Objects are not valid as a React child

When I sort through an array of objects and then output them to the options select, I get errors:
Encountered two children with the same key, Objects are not valid as a React child.
Highlighted ---- important fragments below.
import React, { useState } from "react";
import { DatePicker } from "antd";
import BarChartsMonth from "./../../../components/BarCharts/Barchartmonth";
import BarChartsWeek from "./../../../components/BarCharts/Barchartweek";
import "antd/dist/antd.css";
import { Select } from "antd";
const TeamActivity = () => {
const { MonthPicker, WeekPicker } = DatePicker;
const handleChangeView = val => {
setView(val);
};
+++++++++++++++++++++++++++++++++++++++++++++++++++++
const users = [
{ name: "Peter", surname: "Parker" },
{ name: "Edvard", surname: "Rykinozhnici" },
{ name: "Top", surname: "Ragnakek" },
{ name: "Pavel", surname: "Doorov" }
];
++++++++++++++++++++++++++++++++++++++++++++++++++++++
const UsCollection = users.map((user,i)=> {
return (
<Option key={i} value > {user}</Option>
)
})
++++++++++++++++++++++++++++++++++++++++++++++++++++++
const [view, setView] = useState("Month");
return (
<div className="activity-page">
{" "}
<div className="main-title">Activity of the team</div>
<div className="wrapper-wrapper">
<div className="sort-by">Sort by:</div>
<div className="datepickers-wrapper">
<MonthPicker onChange={(date, type) => handleChange(date, "month")} />
<WeekPicker
placeholder="Select week"
onChange={(date, type) => handleChange(date, "week")}
/>
</div>
<div>
<Select
showSearch
style={{ width: 200 }}
placeholder="Select a person"
optionFilterProp="children"
filterOption={(input, option) =>
option.props.children.toLowerCase().indexOf(input.toLowerCase()) >= 0
}
>
+++++++++++++++++++++++++++++++++++++++++
{UsCollection}
+++++++++++++++++++++++++++++++
</Select>
</div>
</div>
<div className="container ">
<h1 className="week-activity"> {view} activity</h1>
<div className="changes-week-month">
<form>
<input
type="radio"
name="state"
id="week-id"
onClick={() => {
handleChangeView("Week");
}}
/>
<label htmlFor="week-id"> Week </label>
<input
type="radio"
name="state"
id="month-id"
defaultChecked={true}
onClick={() => {
handleChangeView("Month");
}}
/>
<label htmlFor="month-id"> Month </label>
</form>
</div>
{view === "Month" ? <BarChartsMonth /> : <BarChartsWeek />}
</div>
</div>
);
};
export default TeamActivity;
Выполнить кодВернуться к сообщению

Resources