useRef only gets last values from mapped form antd Reactjs - reactjs

I get a bunch of references from an API, I want to insert each Reference with its quantity, I am using antd form useRef
and I get undefined values
const formRef =useRef();
const submitFunction= (values) => {
formRef.current.validateFields().then((values) => {
console.log("Values:", values);
});
};
{reference.map((e, index) => (
<Form ref={formRef}
initialValues={{
["Ref"]: e.reference
}}>
<div>
<Row style={{ backgroundColor: "darkcyan" }} gutter={8}>
<Col span={5}>
<Form.Item label="Ref" name="Ref" labelCol={{ span: 6 }}>
<Input key={index} defaultValue={e.reference} />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item name="quantity">
<InputNumber key={index} />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item>
<Button onClick={() => submitFunction()}>
click me
</Button>
</Form.Item>
</Col>
</Row>
</div>
</Form>
))}
referencesList

Maybe it is too late to answer the question. It seems that because you have a list of Form component and formRef is connected to each form, logically the reference value of the forms are replaced one by one in the formRef till it gets to the last one. If you want to prevent that you can initialize formRef as an empty array like this:
const formRef = useRef([]);
And define ref prop of the Form component like so:
ref={el => {
if (el) formRef.current[index] = el
}}
finally change submitFunction :
const submitFunction = (value) => {
formRef.current.map(form => {
form.validateFields().then((values) => {
console.log("Values:", values);
});
})
};

Related

deselect radio button from array list in react js

I have an array list, where every record will have radio button, when user clicks on one radio it should select it and when user clicks on another radio button the first selected record button should deselect radio button.
Please find sanbox link below:
sandbox link
code:
const handlesubmit = (formdata) => {
console.log(formdata);
};
const renderCard = (card, index) => {
return (
<Col span={7} className="card-background">
<h3 style={{ textAlign: "center" }}>{card.planType}</h3>
<hr />
<Form.Item name="selectedPlan">
<Row>
<Col span={16} offset={2}>
{card.planDetails[0].name}
</Col>{" "}
<Col span={5} offset={1}>
{card.planDetails[0].numOfSession}
</Col>
<Col span={16} offset={2}>
{card.planDetails[1].name}
</Col>{" "}
<Col span={5} offset={1}>
{card.planDetails[1].numOfSession}
</Col>
<Col span={16} offset={2}>
{card.planDetails[2].name}
</Col>{" "}
<Col span={5} offset={1}>
{card.planDetails[2].numOfSession}
</Col>
</Row>
</Form.Item>
<hr />
<div style={{ textAlign: "center" }}>
<Radio onChange={() => setSelectedPlan(card)}>
Pay {card.planAmount}
</Radio>
</div>
</Col>
);
};
you need checked your radio buttons based on plan state
for example
<Radio
checked={selectedPlan === card.planAmount}
onChange={() => setSelectedPlan(card.planAmount)}>
Pay {card.planAmount}
</Radio>
You can define your state like:
const [selectedPlan, setSelectedPlan] = useState(0);
And do something like:
const setSelected = (event, index) => {
setSelectedPlan(index);
};
Finally Change Radio to :
<Radio
checked={selectedPlan == index ? true : false}
name="radio"
onChange={(e) => setSelected(e, index)}
>
Pay {card.planAmount}
</Radio>

Removing complex components from an array in ReactJS

I'm trying to make a list of components. I need to remove the items individually but it seems that the state inside the remove function is always outdated.
For example, if I add 10 authors and click in the 10th author remove button, it'll show me 9 elements (which is already wrong) and if I click on the 2nd author, it shows me just 1 element inside the array. Am I missing something here?
const [authorsFields, setAuthorsFields] = useState<Array<JSX.Element>>([]);
const removeAuthorField = () => {
console.log(authorsFields.length);
}
const removeButton = () => {
return (
<Col className={"d-flex justify-content-end py-1"}>
<Button variant={"danger"} onClick={() => removeAuthorField()}>Remove author</Button>
</Col>
);
}
const authorField = (removable: boolean) => {
return (
<>
<Row className={"mb-2"}>
<Form.Group className={"py-1"}>
<Form.Label>Author name</Form.Label>
<Form.Control type={"text"}/>
</Form.Group>
{removable && removeButton()}
</Row>
</>
);
}
const addAuthorField = () => {
if (authorsFields.length !== 0) {
setAuthorsFields((old) => [...old, authorField(true)]);
} else {
setAuthorsFields([authorField(false)]);
}
}
useEffect(() => {
if (authorsFields.length === 0) {
addAuthorField();
}
}, [])
return (
<>
<Col sm={3} style={{maxHeight: "60vh"}} className={"mt-4"}>
<Row>
{authorsFields}
<Row>
<Form.Group className={"py-1"}>
<Button style={{width: "100%"}} onClick={() => addAuthorField()}>
Add Author
</Button>
</Form.Group>
</Row>
</Row>
</Col>
</>
);
Use the following functional component as an example to modify your code on how to use JSX elements seperated from the state management inside the functional components.
import React, { useState } from "react";
import { Button, Row, Col } from "antd";
function App() {
const [authorsCount, setAuthorsCount] = useState(0);
// Use authorsFields to manage authors details in an array of objects
const [authorsFields, setAuthorsFields] = useState([]);
const removeAuthorField = (id) => {
// To remove relevant author filter out the authors without the relevant id
setAuthorsFields((old) =>
old.filter((authorField) => authorField.id !== id)
);
};
const addAuthorField = () => {
setAuthorsFields((old) => [...old, { id: authorsCount, removable: true }]);
setAuthorsCount((old) => old + 1);
};
return (
<div>
<Col sm={3} style={{ maxHeight: "60vh" }} className={"mt-4"}>
<Row>
{authorsFields.map((authorField) => (
<Row className={"mb-2"}>
<div className={"py-1"}>
<div>{`Author name ${authorField.id}`}</div>
</div>
{authorField.removable && (
<>
<Col className={"d-flex justify-content-end py-1"}>
<Button
variant={"danger"}
onClick={() => removeAuthorField(authorField.id)}
>
Remove author
</Button>
</Col>
</>
)}
</Row>
))}
<Row>
<div className={"py-1"}>
<Button
style={{ width: "100%" }}
onClick={() => addAuthorField()}
>
Add Author
</Button>
</div>
</Row>
</Row>
</Col>
</div>
);
}
export default App;
Following is the view.

how to set the state values in react input?

can you please help me how can i show value of state in input field and also input field is editable. i am trying many tricks but not helpful also can't find in Stackoverflow .......................................
I want show brandcode state property "BrandCode" value in input field................................
here is brandcode return values
brandcode : {
BrandCode: "Nick",
BrandID: 1
}
state = {
brandcode: [],
};
Getbrandcode(brandId) {
getBrandCode(brandId)
.then(res => {
debugger;
//console.log(res);
this.setState({
brandcode: res.data.Data // i want show brandcode values in input
});
});
}
``
its a render.....
``
render() {
// const { formikProps} = this.props
return (
<Formik
enableReinitialize={true}
initialValues={this.masterstyledata}
onSubmit={(values, actions) => {
this.onSaveClick(values);
}}
validationSchema={this.validationSchema}
>
{formikProps => (
<>
<Card>
<CardBody>
{this.state.isLoading && <LoadingPanel />}
<Row>
<Col lg={12}>
<Form>
<FormGroup row>
<Label for="Value" sm={3}>Brand</Label>
<Col sm={3}>
<ComboBoxValue
data={this.state.branddesc}
style={{ width: '100%' }}
name="BrandID"
textField="text"
valueField="Value"
dataItemKey="Value"
onChange={(e) => {
this.BrandCodehandleChange(e);
formikProps.setFieldValue("BrandID", e.target.value)
}}
value={formikProps.values.BrandID}
placeholder="Brand Description"
/>
</Col>
</FormGroup>
<FormGroup row>
//here i want set values
<Label for="BrandCode" sm={3}>Style ID</Label>
<Col sm={3}> <Input sm={3}
type="text"
name="BrandCode"
id="BrandCode"
onChange={formikProps.handleChange('MasterStyleCode')}
value={formikProps.values.MasterStyleCode}
placeholder="Enter Style Id"
/>
<Error>{formikProps.errors.MasterStyleCode}</Error>
</Col>
</FormGroup>
</Form>
</Col>
</Row>
</CardBody>
</Card>
you made a mistake in using handleOnChage and onChange, here:
onChange={formikProps.handleChange('MasterStyleCode')}
at render time this function will be executed and the result is undefined (as you know because it's a void function!), and it's not what you want here, to solve this you have to make a HOF and use setFieldValue if your input name is something different than initialValue key which you want to change it, e.g:
onChange={(event) => {
formikProps.setFieldValue('MasterStyleCode', event.target.value)
}}

I have got the values in this.state i'm filtering the state , but i'm getting the value is null

I'm new to react, i'm working on the search property. I am getting the values from state component when i try to filter it , it's throwing the below error.
"TypeError: Cannot read property 'value' of null"
return (
<div>
<Form>
<Row>
<Col sm={10}>
<FormControl type="text" placeholder="Search" value = {this.state.Searchvalue} onChange = {e => this.setState(prevState => ({
SearchBooks: prevState.SearchBooks.filter(book => book.title === e.target.value)
}))} />
</Col>
<Col sm={2}>
<Button variant="outline-success">Search</Button>
</Col>
</Row>
</Form>
<br/>
{this.state.SearchBooks.map(book => (
<div>
<Card key = {book.id}>
<Card.Header as="h5">{book.bookname}</Card.Header>
<Card.Body>
<Card.Title>{book.title}</Card.Title>
<Card.Text>
Author : {book.authorname}<br/>
Email id : {book.aemailid}<br/>
ISBN : {book.isbn}<br/>
</Card.Text>
<Button variant="danger" onClick={ () => this.removeBook(book.id)}>Delete Book</Button>
<Button variant="primary" onClick={() => this.flagedit(true,book)}>Edit Book</Button>
{/* <Button variant="primary" onClick={() => this.editmodal(book.bookname)}>Edit Book</Button> */}
{this.editmodal()}
</Card.Body>
<Card.Footer className="text-muted">count : {book.count}</Card.Footer>
</Card>
<br/>
</div>
))}
</div>
)
}
Because of performance concerns, react reuses event object, setting them to null between different events. So at the time your stateUpdated function is executed the value of event is null, and so trying to read null.value will throw "TypeError: Cannot read property 'value' of null"
To solve it, you can do something like this
<FormControl
type="text"
placeholder="Search"
value={this.state.Searchvalue}
onChange={e => {
const currentValue = e.target.value;
this.setState(prevState => ({
SearchBooks: prevState.SearchBooks.filter(
book => book.title === currentValue
),
}));
}}
/>;
The problem is because you are using e.target.value inside setState().
Two factors affecting this:
Since onChange is a Synthetic Event, it will be reused after it is invoked. Thus, e is cleared / nullified after onChange
setState() is async.
Thus, you could either:
1. Declare a variable:
onChange = (e) => {
const eventValue = e.target.value // declare a variable
this.setState(prevState => ({
SearchBooks: prevState.SearchBooks.filter(book => book.title === eventValue)
})
}
<FormControl type="text"
onChange={onChange}
/>
or
2. Persist the event via event.persist()
onChange = (e) => {
e.persist() // persist event
this.setState(prevState => ({
SearchBooks: prevState.SearchBooks.filter(book =>
book.title === event.target.value
)
})
}

How to call OnChange function in react using withformik with antd component?

Here I'm calling onChange function on Formik Field but its not calling? How to call custom function on a Formik field?
This is my custom function under React Component:
onStudentScore = (value, form) => {
alert("called");
const maxScore = value.writtenexammaxscore;
console.log(maxScore);
form.getFieldValue("writtenexammaxscore", maxScore);
if (maxScore > form.getFieldValue("writtenexamstudentsscore")) {
alert("MaxScore is less than StudentScore");
}
};
And my Form is created under render and write a onChange function on a StudentScore field. But it's not called? How to call this function?
render() {
const { values, handleSubmit} = this.props
return (
return (
<div>
<h5 align="left">MidTerm Form</h5>
<Card>
<Form onSubmit={handleSubmit}>
<Row>
<Col span={4}>
<b>Written Exam:</b>
</Col>
<Col span={2}>
<Field
name="writtenexammaxscore"
component={AntInput}
type="text"
style={{ width: 40 }}
/>
</Col>
<Col span={2}>outof</Col>
<Col span={3}>
<Field
name="writtenexamstudentsscore"
component={AntInput}
type="text"
style={{ width: 40 }}
onChange={this.onStudentScore}
/>
// I wrote the function on field this way
</Col>
<Col span={2}>
<Divider type="vertical" />
</Col>
</Row>
<Row>
<Col span={10} />
<Col span={8} push={10}>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Col>
</Row>
</Form>
</Card>
</div>
);
}
const MidTermForm = withFormik({
mapPropsToValues: () => ({
writtenexammaxscore: '',
writtenexamstudentsscore: '',
oralexammaximumscore: '',
oralexamstudentsscore: '',
}),
handleSubmit(values, { resetForm }) {
resetForm();
console.log(values)
}
})(MidTermFormComponent)
export default MidTermForm
I tried by extending yup validation schema. Instead of calling a function in onChange
check this code sandbox

Resources