How to get the difference from dyanamically added fields- react - javascript

I'm new to Reactjs. All I'm trying to do is as follow:
I've three fields: ENTRY, EXIT, TOTAL
TOTAL = EXIT - ENTRY
Example:
ENTRY | EXIT | Total
1 | 2 | 1
2 | 4 | 2
3 | 6 | 3
5 | 10| 5
Here ENTRY and EXIT are dynamically added fields when +Add button is clicked. I've been able to add the fields dynamically, but I am not getting the TOTAL value.
var entry;
var exit;
class Calculator extends React.Component {
state = {
values: [{id:0,exit:0,entry:0}],
total:[]
};
add() {
this.setState(prevState => prevState.values.push(null));
}
changeVal(val, index, key) {
if(key == 'exit'){
exit = val;
}else{
entry =val;
}
this.setState(prevState => (prevState.values[index] = {id:index, exit:val, entry: val}));
}
getTotal() {
let total = 0;
for (let i = 0; i < this.state.values.length; i++) {
if (this.state.values[i] !== null) {
total = this.state.values[i].exit - this.state.values[i].entry;
}
}
return total;
}
render() {
return (
<div>
{this.state.values.map((val, index, key) => (
<div key={index}>
<input
onChange={e => this.changeVal(e.target.value, index, 'exit')}
name={ `exit[${index}]` }
type="number"
value={val}
placeholder="Enter a value"
/>
<input
onChange={e => this.changeVal(e.target.value, index, 'entry')}
name={ `entry[${index}]` }
type="number"
value={val}
placeholder="Enter a value"
/>
<input
name={ `total[${index}]` }
type="number"
value={this.state.total}
/>
</div>
))}
<button onClick={this.add.bind(this)}> +Add</button>
</div>
);
}
}
ReactDOM.render(<Calculator /> , document.getElementById('calculator'));
Also please tell me if it is the best approach to add input fields dynamically. Thank you

You can do something like this:
var entry;
var exit;
class Calculator extends React.Component {
state = {
values: [{ id: 0, exit: 0, entry: 0 }],
total: []
};
add() {
let { values } = this.state;
values.push({ id: 0, exit: 0, entry: 0 });
this.setState({ values });
}
changeVal(val, index, key) {
let { values } = this.state;
values[index][key] = val;
this.setState({ values });
}
getTotal(data) {
return Number(data.exit) - Number(data.entry);
}
render() {
let { values, total } = this.state;
return (
<div>
{values.map((val, index, key) => {
return (
<div key={index}>
<input
onChange={e => this.changeVal(e.target.value, index, "exit")}
name={`exit[${index}]`}
type="number"
value={val.exit}
placeholder="Enter a value"
/>
<input
onChange={e => this.changeVal(e.target.value, index, "entry")}
name={`entry[${index}]`}
type="number"
value={val.entry}
placeholder="Enter a value"
/>
<input
name={`total[${index}]`}
type="number"
value={this.getTotal(val)}
/>
</div>
);
})}
<button onClick={this.add.bind(this)}> +Add</button>
</div>
);
}
}
Here is the live demo
Hope it helps :)

There are few place where your code misbehaves.
<input
onChange={e => this.changeVal(e.target.value, index, 'exit')}
name={ `exit[${index}]` }
type="number"
value={val.exit}
placeholder="Enter a value"
/>
You have given entire object to value instead you to should give property (val.exit).
While adding you need to push an object to value array.
add() {
this.setState(prevState => prevState.values.push({id:this.state.values.length,exit:0,entry:0}));}
while changing values, you need to change the value for specific property.
changeVal(val, index, key) {
if(key == 'exit'){
exit = val;
}else{
entry =val;
}
var changeVal = this.state.values[index] || {id:index, exit:0, entry: 0};
changeVal[key] = val;
this.setState(prevState => ( prevState.values[index] = changeVal));}
For total, you need to call the getTotal function.
<input
name={ `total[${index}]` }
type="number"
value={this.getTotal(index)}
/>
Here is a live demo.

Related

Logic of updating an object in react with useState

I have a component renderRoyaltyAccount, that gets rendered x number of times depending on the input that sets royaltyAccount.
In this component I have 2 fields, one for the name of the account, and the second a percentage.
What I wanted to do is depending of the number of accounts to create, create an object with those two fields for each, example :
If he chooses to create two accounts , to have a the end (what I thought but could be not the best choice :) ) :
{
1: {
"account": "test1",
"percentage": 2,
},
2: {
"account": "test#",
"percentage": 0.5
}
}
I tried with a useState and updating it with onChange with inputs, but it was a mess LOL.
If anyone could help me with this state, and specially the logic with objects and hooks. Thank you
export default function FormApp() {
const [royaltyAccount, setRoyaltyAccount] = useState(1);
const [allAccounts, setAllAccounts] = useState ({
{
"account": "",
"percentage": 1,
},
})
const renderRoyaltyAccounts = () => {
let items = [];
for (let i = 0; i < royaltyAccount; i++) {
items.push(
<div key={i}>
<div>
<label>Royalty Account n° {i + 1}</label>
<input onChange={()=> setAllAccounts(???)} type="text"/>
</div>
<div>
<label>Royalty %</label>
<input onChange={()=> setAllAccounts(???)} type="text"/>
</div>
</div>
)
}
return items;
}
return (
<>
<label> Royalty account(s)</label>
<input onChange={(e) => { setRoyaltyAccount(e.target.value)}} type="number"/>
{
renderRoyaltyAccounts()
}
</>
)
}
Dynamically compute the allAccounts state array from the initial royaltyAccount state value. Add an id property to act as a GUID for each account object.
Create a handleRoyaltyAccountChange onChange handler to either append a computed diff of the current allAccounts array length to the new count value, or to slice up to the new count if less.
Create a handleAccountUpdate onChange handler to shallow copy the allAccounts state array and update the specifically matching account object by id.
Give the inputs a name attributeand pass the mappedallAccountselement object's property as thevalue` prop.
Code:
import { useState } from "react";
import { nanoid } from "nanoid";
function FormApp() {
const [royaltyAccount, setRoyaltyAccount] = useState(1);
const [allAccounts, setAllAccounts] = useState(
Array.from({ length: royaltyAccount }).map(() => ({
id: nanoid(),
account: "",
percentage: 1
}))
);
const handleRoyaltyAccountChange = (e) => {
const { value } = e.target;
const newCount = Number(value);
setRoyaltyAccount(newCount);
setAllAccounts((accounts) => {
if (newCount > accounts.length) {
return accounts.concat(
...Array.from({ length: newCount - accounts.length }).map(() => ({
id: nanoid(),
account: "",
percentage: 1
}))
);
} else {
return accounts.slice(0, newCount);
}
});
};
const handleAccountUpdate = (id) => (e) => {
const { name, value } = e.target;
setAllAccounts((accounts) =>
accounts.map((account) =>
account.id === id
? {
...account,
[name]: value
}
: account
)
);
};
return (
<>
<label> Royalty account(s)</label>
<input
type="number"
onChange={handleRoyaltyAccountChange}
value={royaltyAccount}
/>
<hr />
{allAccounts.map((account, i) => (
<div key={account.id}>
<div>
<div>Account: {account.id}</div>
<label>
Royalty Account n° {i + 1}
<input
type="text"
name="account"
onChange={handleAccountUpdate(account.id)}
value={account.account}
/>
</label>
</div>
<div>
<label>
Royalty %
<input
type="text"
name="percentage"
onChange={handleAccountUpdate(account.id)}
value={account.percentage}
/>
</label>
</div>
</div>
))}
</>
);
}

React dynamic form bug

I've created script for dynamic form, but there's 2 things which I can't get and my head is exploding right now, hopefully somebody would help me with that.
After creating new fields - I can't remove fields depends on button which was clicked.
And after removing some of those fields, I have this error with fieldsenter image description here
import React from "react";
import {useState , useEffect} from "react";
import ReactDOM from "react-dom";
import "./index.css";
const Form = () =>{
const [fieldsLength, fieldsLengthChanger] = useState(1);
const [fields, fieldsChanger] = useState([{
id : 1,
name: "",
phone: "",
age: ""
}])
return (
<>
<div className="form__wrapper">
<h2>Form </h2>
{
fields.map((elem, index) => {
return(
<FormElement {...elem} fields={fields} fieldsChanger={fieldsChanger} fieldsLength={fieldsLength} fieldsLengthChanger={fieldsLengthChanger}/>
)
})
}
<AddMore fieldsLength={fieldsLength} fieldsLengthChanger={fieldsLengthChanger} fields={fields} fieldsChanger={fieldsChanger}/>
</div>
</>
)
}
const FormElement = ({fieldsLength ,...props}) =>{
function inputHandler(e, id){
console.log(e.target.name);
const values = [...props.fields];
values[id-1][e.target.name] = e.target.value;
props.fieldsChanger(values);
}
function removeElement(e,id){
e.preventDefault();
var arr = [...props.fields];
const newArray = arr.filter(function(elem,index){
console.log("index:" , index, "ID : ", id);
if (index + 1 != id){
return elem;
}
});
// console.log(newArray);
// arr.splice(3, 1);
props.fieldsChanger([])
props.fieldsChanger(newArray);
}
return (
<div className="group__form">
<div className="form__element">
<input type="text" value={props.fields.name} name="name" onChange={e => inputHandler(e , props.id)} />
</div>
<div className="form__element">
<input type="text" value={props.fields.phone} name="phone" onChange={e => inputHandler(e , props.id)}/>
</div>
<div className="form__element">
<input type="text" value={props.fields.age} name="age" onChange={e => inputHandler(e , props.id)}/>
</div>
{
fieldsLength > 1 ? <div className="remove__field">
<a href="#" onClick={e=>removeElement(e , props.id)}>Remove</a>
</div> : ""
}
</div>
)
}
const AddMore = (props) =>{
function addMore(){
props.fieldsLengthChanger(props.fields.length + 1);
props.fieldsChanger([...props.fields, {id:props.fields.length + 1 , name: "" , phone : "" , age :''} ]);
}
return (
<div className="add__more">
<a href="#" onClick={e=> addMore()}>Add element</a>
</div>
)
}
ReactDOM.render(<Form/> , document.getElementById("root"));
Where I'm wrong - would be really helpfull to understand what is the problem
Always use key when rendering list.
<FormElement key={elem.id} {...elem} ...
https://reactjs.org/docs/lists-and-keys.html#keys
1. You should use the props.id to remove a form instead of using index.
e.g. this must be a bug.
if (index + 1 != id) {
return elem;
}
2. And you should use id by the unique value generation instead of using array's length.
3. You should provide the key prop in the render of the form fields. Otherwise, React can't distinguish forms in rendering.
And the key should be unique whenever you add or remove items.
e.g. See the updated code. You need to use elem.id. (Of course, you should generate id in the add method.
{fields.map((elem, index) => {
return (
<FormElement
key={elem.id}
{...elem}
fields={fields}
fieldsChanger={fieldsChanger}
fieldsLength={fieldsLength}
fieldsLengthChanger={fieldsLengthChanger}
/>
);
})}
4. You could basically use a timestamp. Please use your own generation logic in the production. You can use uuid generation package.
{
id: new Date().getTime(),
name: "",
phone: "",
age: ""
}
My advices:
You don't need to use this state variable const [fieldsLength, fieldsLengthChanger] = useState(1);
Because we can get this value by fields.length.
There are a few problems in terms of components design. e.g. Please try to define addMore() in form then you don't need to pass fields, fieldsChanger as props.
Here is a full working code with your old code commented.
const Form = () => {
const [fieldsLength, fieldsLengthChanger] = useState(1);
const [fields, fieldsChanger] = useState([
{
id: new Date().getTime(),
name: "",
phone: "",
age: ""
}
]);
return (
<>
<div className="form__wrapper">
<h2>Form </h2>
{fields.map((elem, index) => {
return (
<FormElement
key={elem.id}
{...elem}
fields={fields}
fieldsChanger={fieldsChanger}
fieldsLength={fieldsLength}
fieldsLengthChanger={fieldsLengthChanger}
/>
);
})}
<AddMore
fieldsLength={fieldsLength}
fieldsLengthChanger={fieldsLengthChanger}
fields={fields}
fieldsChanger={fieldsChanger}
/>
</div>
</>
);
};
const FormElement = ({ fieldsLength, ...props }) => {
function inputHandler(e, id) {
console.log(e.target.name);
const values = [...props.fields];
const item = values.find((x) => x.id === props.id);
if (item) {
item[e.target.name] = e.target.value;
}
// values[id - 1][e.target.name] = e.target.value;
props.fieldsChanger(values);
}
function removeElement(e, id) {
e.preventDefault();
var arr = [...props.fields];
const newArray = arr.filter(function (elem, index) {
/*console.log("index:", index, "ID : ", id);
if (index + 1 != id) {
return elem;
}*/
return elem.id !== id;
});
// console.log(newArray);
// arr.splice(3, 1);
props.fieldsChanger([]);
props.fieldsChanger(newArray);
}
return (
<div className="group__form">
<div className="form__element">
<input
type="text"
value={props.fields.name}
name="name"
onChange={(e) => inputHandler(e, props.id)}
/>
</div>
<div className="form__element">
<input
type="text"
value={props.fields.phone}
name="phone"
onChange={(e) => inputHandler(e, props.id)}
/>
</div>
<div className="form__element">
<input
type="text"
value={props.fields.age}
name="age"
onChange={(e) => inputHandler(e, props.id)}
/>
</div>
{fieldsLength > 1 ? (
<div className="remove__field">
<a href="#" onClick={(e) => removeElement(e, props.id)}>
Remove
</a>
</div>
) : (
""
)}
</div>
);
};
const AddMore = (props) => {
function addMore() {
props.fieldsLengthChanger(props.fields.length + 1);
props.fieldsChanger([
...props.fields,
//{ id: props.fields.length + 1, name: "", phone: "", age: "" }
{ id: new Date().getTime(), name: "", phone: "", age: "" }
]);
}
return (
<div className="add__more">
<a href="#" onClick={(e) => addMore()}>
Add element
</a>
</div>
);
};

How to set multiple object value with special key on react js

i need your help to set the new value in multiple object. I had object like this:
constructor(props){
this.state = {
objData : [{
score:{q1:null,q2:null,q3:null},
data:{id:123, name:"Steven CHS"}
},
{
score:{q1:null,q2:null,q3:null},
data:{id:124, name:"Christian"}
},
]
}
}
and i would like to change the value by key q1,q2, anda q3. When i tried to use destructor like this, it's not working.
const handleChangeScore = (e,type,id) =>{
const cScore = e.target.value;
this.setState((state) => {
return {
objData: state.objData.map((item) => {
if(item.data.id !== e.target.name) return item;
else return {...item.score.q1, cScore};
})
};
});
}
this is the JSX where handleChangeScore() is used:
this.state.objData .map((v,index)=>(
<tr>
<td>{index+1}</td>
<td>{v.data.id} - {v.data.name}</td>
<td><input type="text" name={v.data.id} className="form-control" onChange={(e)=>handleChangeScore(e,"q1",v.data.id)} defaultValue={(v.score.q1) ? v.score.q1 : 0} /></td>
<td><input type="text" name={v.data.id} className="form-control" onChange={(e)=>handleChangeScore(e,"q2",v.data.id)} defaultValue={(v.score.q2) ? v.score.q2: 0} /></td>
</tr>
))
The problem is when i use destructor to change the value on multiple object with specific key its not work or not change the value. Can anyone help me to fix my code ? Here's the full code in codesanbox
Few things to be fixed
Your item.data.id is number and e.target.name is string. To compare them without type comparison use != instead of !==.
The else block should be corrected as below.
handleChangeScore = (e, type, id) => {
const cScore = e.target.value;
this.setState((state) => {
return {
...state,
objData: state.objData.map((item) => {
if (item.data.id != e.target.name) return item;
else {
return { ...item, score: { ...item.score, [type]: cScore } };
}
})
};
});
};
Code Sandbox
Try below code no need to use map(). just pass the index in this.handleChangeScore() function !
And put handleChangeScore() this function in outside of render() !
export class App extends Component {
constructor(props) {
super(props);
this.state = {
objData: [
{
score: { q1: null, q2: null, q3: null },
data: { id: 123, name: "Steven CHS" }
},
{
score: { q1: null, q2: null, q3: null },
data: { id: 124, name: "Christian" }
}
]
};
}
handleChangeScore = (value, index, childObj) => {
this.state.objData[index].score[childObj] = value;
this.setState(this.state);
};
render() {
return (
<div className="App">
<table border="1">
{this.state.objData.map((v, index) => (
<tr>
<td>{index + 1}</td>
<td>
{v.data.id} - {v.data.name}
</td>
<td>
<input
type="text"
name={v.data.id}
className="form-control"
onChange={(e) => this.handleChangeScore(e.target.value, index, "q1")}
defaultValue={v.score.q1 ? v.score.q1 : 0}
/>
</td>
<td>
<input
type="text"
name={v.data.id}
className="form-control"
onChange={(e) => this.handleChangeScore(e.target.value, index, "q2")}
defaultValue={v.score.q2 ? v.score.q2 : 0}
/>
</td>
</tr>
))}
</table>
</div>
);
}
}
export default App;

How to save input entered by the user in a state which is an array in React

The whole idea is to take users input in a form and display their input in a JSON object. In state I have an array and inside it another array.
My Form.js looks like this,
state= {
groups:[{
typeA:[{}],
typeB:[{}]
}],
credentials: false
};
change = e =>{
this.setState({[e.target.name]: e.target.value})
};
handleSubmit(event) {
event.preventDefault();
this.setState({
credentials: true
});
}
render(){
return(
<div class="classform">
<form >
<label>
Field1:
<br/>
<input type="text"
name="typeA"
placeholder="Type A"
//store it as the first element of the type A
value={this.state.groups.typeA[0]}
onChange={this.change.bind(this)}
/>
//other fields with the same code
Subsequently, Field2 will be stored as the second element of type A
Then, Field3 and Field4 will be stored as 2 of type B array
I expect the code to give me an output like :
"typeA": ["field1 value", "field2 value"],
"typeB": ["field3 value", "field4 value"]}
I'm a beginner with React and I'm not able to store the field values in the state which is an array.
For the sake of simplicity, I will recommend below solution,
Instead of having a nested array in the state, you can manage the input values in the different state variables and at the time of submitting, change them to the output you want.
state = {
field1: '',
field2: '',
field3: '',
field4: '',
}
change = e => {
this.setState({[e.target.name]: e.target.value})
};
handleSubmit(event) {
event.preventDefault();
const { field1, field2, field3, field4 } = this.state;
// This is your output
const output = [{typeA: [field1, field2], typeB: [field2, field3]}];
this.setState({
credentials: true
});
}
render(){
return(
<div class="classform">
<form >
<label>
Field1:
<br/>
<input type="text"
name="field1"
placeholder="Type A"
value={this.state.field1}
onChange={this.change}
/>
</label>
<label>
Field2:
<br/>
<input type="text"
name="field2"
placeholder="Type A"
value={this.state.field2}
onChange={this.change}
/>
</label>
try this:
import React, { Component } from "react";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
groups: [
{
typeA: [{}],
typeB: [{}]
}
],
credentials: false
};
}
change = (e, key) => {
let { groups } = this.state;
let myVal = groups[0][e.target.name];
// or if you want to add value in an object likr [{value: 'abcd'}]
myVal[0][key] = e.target.value;
groups[0][e.target.name] = myVal;
console.log("TCL: App -> groups", groups);
this.setState({ groups });
};
render() {
return (
<div>
<input
type="text"
name="typeA"
placeholder="Type A"
value={this.state.groups[0].typeA[0].value2}
onChange={e => this.change(e, "value2")}
/>
<input
type="text"
name="typeA"
placeholder="Type A2"
value={this.state.groups[0].typeA[0].value}
onChange={e => this.change(e, "value")}
/>
<br />
<input
type="text"
name="typeB"
placeholder="Type b"
value={this.state.groups[0].typeB[0].value}
onChange={e => this.change(e, "value")}
/>
</div>
);
}
}
Give each input a custom attribute, for example data-group="typeA". In your on change function get that value and add the values to the correct array.
<input
type="text"
name="col2"
placeholder="Type A"
data-group="typeA" // add custom attribute typeA | typeB etc.
onChange={e => this.change(e)}
/>
In your change handle get the custom attribute, and use it to add the value to the correct array.
change = e => {
// create a copy of this.state.groups
const copyGroups = JSON.parse(JSON.stringify(this.state.groups));
// get data-group value
const group = event.target.dataset.group;
if (!copyGroups[0][group]) {
copyGroups[0][group] = []; // add type if it doesn't exists
}
const groups = copyGroups[0][group];
const index = this.findFieldIndex(groups, e.target.name);
if (index < 0) {
// if input doesn't exists add to the array
copyGroups[0][group] = [...groups, { [e.target.name]: e.target.value }];
} else {
// else update the value
copyGroups[0][group][index][e.target.name] = e.target.value;
}
this.setState({ groups: copyGroups });
};
pre {outline: 1px solid #ccc; padding: 5px; margin: 5px; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
<div id="root"></div>
<script type="text/babel">
function formatState(json) {
if (typeof json != 'string') {
json = JSON.stringify(json, undefined, 2);
}
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
return json.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, (match) => match);
}
const Credentials = ({ value }) => {
return <pre>{formatState(value)}</pre>;
};
class App extends React.Component {
state = {
groups: [
{
typeA: [],
typeB: []
}
],
credentials: false
};
handleSubmit = event => {
event.preventDefault();
this.setState({
credentials: true // display Credentials component
});
};
// get the current input index in the array typeA | typeB
findFieldIndex = (array, name) => {
return array.findIndex(item => item[name] !== undefined);
};
change = e => {
// create a copy of this.state.groups
const copyGroups = JSON.parse(JSON.stringify(this.state.groups));
// get data-group value
const group = event.target.dataset.group;
if (!copyGroups[0][group]) {
copyGroups[0][group] = []; // add new type
}
const groups = copyGroups[0][group];
const index = this.findFieldIndex(groups, e.target.name);
if (index < 0) {
// if input doesn't exists add to the array
copyGroups[0][group] = [...groups, { [e.target.name]: e.target.value }];
} else {
// update the value
copyGroups[0][group][index][e.target.name] = e.target.value;
}
this.setState({ groups: copyGroups });
};
removeKey = (key) => {
const temp = {...this.state};
delete temp[key];
return temp;
}
render() {
return (
<div>
<input
type="text"
name="col1"
placeholder="Type A"
data-group="typeA"
onChange={e => this.change(e)}
/>
<input
type="text"
name="col2"
placeholder="Type A"
data-group="typeA"
onChange={e => this.change(e)}
/>
<input
type="text"
name="col2"
placeholder="Type B"
data-group="typeB"
onChange={e => this.change(e)}
/>
<input
type="text"
name="typec"
placeholder="Type C | New Type"
data-group="typeC"
onChange={e => this.change(e)}
/>
<input
type="text"
name="typed"
placeholder="Type D | New Type"
data-group="typeD"
onChange={e => this.change(e)}
/>
<button onClick={this.handleSubmit}>Submit</button>
{this.state.credentials && (
<Credentials value={JSON.stringify(this.removeKey('credentials'), undefined, 2)} />
)}
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
</script>

front-end just remove only last item in array

I'm having a issue with React.
my parent component:
class RoomPrice extends React.Component {
constructor(props){
super(props)
this.state = {
room: this.props.room,
prices: []
};
this.handleDeletePrice = this.handleDeletePrice.bind(this);
}
handleDeletePrice(price_index){
let prices = this.state.prices;
prices.splice(price_index, 1);
this.setState({prices: prices});
}
listPrices(){
console.log(this.state.prices)
return this.state.prices.map((item, index) => {
return (
<AdditionalPrice
key={index}
price={item}
index={index}
handleDeletePrice={this.handleDeletePrice}
/>
)
});
}
renderBasePrice(){
return(
<div id="list_prices">
{ this.listPrices() }
</div>
)
}
render(){
return(
<div>
{this.renderBasePrice()}
</div>
)
}
}
my child component
class AdditionalPrice extends React.Component {
constructor(props){
super(props)
this.state = {
price: this.props.price
}
this.handleKeyChange = this.handleKeyChange.bind(this);
this.handleValueChange = this.handleValueChange.bind(this);
this.handleDeletePrice = this.handleDeletePrice.bind(this);
}
componentWillReceiveProps(nextProps){
this.setState({price: nextProps.price})
}
handleKeyChange(event){
let price = this.state.price;
price.key = event.target.value
this.setState({price: price})
}
handleValueChange(event){
let price = this.state.price;
price.value = event.target.value
this.setState({price: price})
}
handleDeletePrice(){
this.props.handleDeletePrice(this.props.index);
}
renderForm(){
let key = this.state.price.key;
let value = this.state.price.value;
return(
<div className="form-row">
<div className="col-5">
<input type="text" className="form-control" placeholder="Key" onChange={this.handleKeyChange} required/>
</div>
<div className="col-5">
<input type="number" className="form-control" placeholder="Value" onChange={this.handleValueChange} required/>
</div>
<div className="col-2">
<button className="btn btn-warning" type="button" onClick={this.handleDeletePrice}>
<i className="material-icons">delete_forever</i>
</button>
</div>
<input type="hidden" className="form-control" name={"base_price["+key+"]"} value={value} />
</div>
)
}
render() {
return(
<div>
{this.renderForm()}
</div>
)
}
}
i try to delete a item which was get in children, but it always removes last element instead. I thought it have some problem with index
I want to delete the particular element, it always deletes the last element from the render list array.
please help me to sort this problem
Try doing this instead.
handleAddNewPrice(){
const { prices } = this.state;
let new_price = {"key": "", "value": ""}
this.setState({ prices: [...prices, new_price] })
}
Edit
and also this:
handleDeletePrice(price_index){
let prices = [...this.state.prices]; //make a seperate copy of state.
prices.splice(price_index, 1);
this.setState({prices: prices});
}
Problem is in your props. The props.index is received once, so if you want to the delete function worked you need use props.index as a state like price. This is sample codes you need to change in the AdditionalPrice Component:
this.state = {
price: this.props.price,
index: this.props.index
}
componentWillReceiveProps(nextProps){
this.setState({
price: nextProps.price,
index: nextProps.index
})
}
handleDeletePrice(){
this.props.handleDeletePrice(this.state.index);
}
i found the problem
my field in child component haven't set the value. see below
<input type="text" className="form-control" placeholder="Key" value={key} onChange={this.handleKeyChange} required/>
thanks all

Categories