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);
});
})
};
The form has two elements.
When I select autocomplete value from emal element and then try to input a text value to titl field, the autocomplete value is automatically changed to empty.
What should I do to fix this issue?
I have tried to change formik initialValues using states but it's not working.
sorry for the language issue. Thanks in advance!
class TicketNew extends React.Component{
state = {
clearForm:false,
spinner:false,
closeForm:false,
emailsugges:[],
}
loadAlldata() {
this.setState({
spinner:false,
})
axios.post(baseUrl+'/api/load_company_list')
.then(res => {
const comanyList = res.data;
const emls = comanyList.emls.map(function(item, i){
return {
value:item.tci, title:item.tcc
}
})
this.setState({
emailsugges:emls
})
})
this.setState({
spinner:false,
})
};
componentDidMount(){
this.loadAlldata();
};
render(){
return(
<React.Fragment>
<Formik
initialValues={{ emal: "", titl: "" }}
validationSchema={formSchema}
>
{
({ errors,
touched,
handleSubmit,
isSubmitting,
handleBlur,
values,
resetForm
}) => (
<div>
<Form onSubmit={handleSubmit}>
<Card>
<CardHeader></CardHeader>
<CardBody>
<Row>
<Col md="5" sm="12">
<FormGroup row className="position-relative">
<Col md="4">
<span>Title</span>
</Col>
<Col md="8">
<Field
type="text"
name="titl"
id="titl"
className={`
form-control ${errors.titl && touched.titl && "is-invalid"}
`}
onBlur={handleBlur('titl')}
/>
{errors.titl &&
touched.titl ? (
<div className="invalid-tooltip mt-25">
{errors.titl}
</div>
) : null}
</Col>
</FormGroup>
</Col>
<Col md="2" sm="12"></Col>
<Col md="5" sm="12">
<FormGroup row className="position-relative"
style={{display:rqst!="1"?'none':''}}
>
<Col md="4">
<span>Email Address</span>
</Col>
<Col md="8">
<Field name="emal"
component={ ({field, form}) =>
<AutoComplete
type="email"
name="emal"
id="emal"
suggestions={this.state.emailsugges}
value={
this.state.emailsugges ?
this.state.emailsugges.find(option =>
option.value === field.value)
: ''}
className={`
form-control ${errors.emal && touched.emal && "is-invalid"}
`}
filterKey="title"
suggestionLimit={4}
/>}
/>
{errors.emal &&
touched.emal ? (
<div className="invalid-tooltip mt-25">
{errors.emal}
</div>
) : null}
</Col>
</FormGroup>
</Col>
</Row>
</CardBody>
</Card>
</Form>
</div>
)}
</Formik>
</React.Fragment>
)
}
};
export default TicketNew;
Sorry for my english.
Like in this example
https://codesandbox.io/s/wonderful-lichterman-br63z?file=/index.js
Form.List is rendering the Array of "Fields" which initally is empty.
I would like to put my own array to be rendered from the start.
Expected result
you can do it using initialValues prop of Form.
Working example: https://codesandbox.io/s/bold-turing-g8ft6?file=/index.js
Docs: https://ant.design/components/form/#API
The docs are a bit short on explanation for the Form.List, and since a code sample is worth a thousand words...
This renders the dynamic form list with one item already visible:
const initialValues = {
users: [
{ age: undefined } // undefined will render the placeholder
]
};
<Form initialValues={initialValues}>
<Form.List name="users">
{(fields, { add }) => {
return (
<div>
{fields.map(field => (
<Row key={field.key}>
<Col>
<Form.Item
placeholder="age"
name={[field.age, 'age']}
>
<Input />
</Form.Item>
</Col>
<Col>
<Form.Item
placeholder="sex"
name={[field.sex, 'sex']}
>
<Input />
</Form.Item>
</Col>
<Col>
<Form.Item
placeholder="name"
name={[field.name, 'name']}
>
<Input />
</Form.Item>
</Col>
</Row>
))}
<button onClick={() => add()}>Add</button>
</div>
)
}}
</Form.List>
</Form>
I have a component, DeleteRoute, which is just a wrapper around a Modal. It allows me to delete a "Route" entity.
I am using React as well as Redux to maintain data and state.
I am struggling with the correct architecture to make the modal work. I didn't like having all of the state in the parent container because it made the parent cluttered. So I put the redux actions inside the modal. This way I pass in a route from the parent, but call "deleteRoute" from the redux store inside the DeleteRoute component, and I can display success and error messages.
This all works great, except it I close and re-open the modal, the previous success/error message is still displayed. This is because the closing/opening is done with a toggle from the parent, but the parent can't reset the child props.
I thought I could just pass the success and error properties in the parent, and anytime the parent re-renders it would reset those, but it isn't (despite it re-rendering when isOpen changes).
class DeleteRoute extends React.Component {
constructor(props) {
super(props);
this.deleteRoute = this.deleteRoute.bind(this);
}
deleteRoute() {
this.props.deleteRoute(this.props.route);
}
render() {
var route = this.props.route || {};
return (
<div>
<Modal
isOpen={this.props.isOpen}
toggle={this.props.toggle}
>
<ModalHeader toggle={this.props.toggle}>Delete Route</ModalHeader>
<ModalBody>
{this.props.isLoading && <Spinner color="primary" />}
<Alert color="danger" isOpen={this.props.error}>{this.props.error}</Alert>
<Alert color="success" isOpen={this.props.success}>Deleted successfully</Alert>
<Form>
<Row form>
<Col>
<FormGroup>
<Label for="CssPlatform">Css Platform</Label>
<Input disabled name="CssPlatform" type="text" value={route.CSSPlatform} />
</FormGroup>
</Col>
<Col>
<FormGroup>
<Label for="ProdManager">Prod Manager</Label>
<Input disabled name="ProdManager" type="text" value={route.ProdManager} />
</FormGroup>
</Col>
</Row>
<Row form>
<Col>
<FormGroup>
<Label for="CssProduct">Css Product</Label>
<Input disabled name="CssProduct" type="text" value={route.CSSProduct} />
</FormGroup>
</Col>
<Col>
<FormGroup>
<Label for="ProgSupervisor">Prog Supervisor</Label>
<Input disabled name="ProgSupervisor" type="text" value={route.ProgSupervisor} />
</FormGroup>
</Col>
</Row>
<Row form>
<Col>
<FormGroup>
<Label for="CssSubProduct">Css SubProduct</Label>
<Input disabled name="CssSubProduct" type="text" value={route.CSSSubProduct} />
</FormGroup>
</Col>
<Col>
<FormGroup>
<Label for="RallyProject">Rally Project</Label>
<Input disabled name="RallyProject" type="text" value={route.RallyProject} />
</FormGroup>
</Col>
</Row>
<Row form>
<Col>
<FormGroup check inline>
<Label check>
<Input disabled name="CssProductActive" type="checkbox" checked={route.CSSProductActive} />
Css Product Active
</Label>
</FormGroup>
</Col>
<Col>
<FormGroup check inline>
<Label check>
<Input disabled name="CssSubProductActive" type="checkbox" checked={route.CSSSubProductActive} />
Css SubProduct Active
</Label>
</FormGroup>
</Col>
</Row>
</Form>
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={this.deleteRoute}>Delete Route</Button>{' '}
<Button color="secondary" onClick={this.props.toggle}>Cancel</Button>
</ModalFooter>
</Modal>
</div>
);
}
}
export default connect(
state => state.deleteRouteReducer,
dispatch => bindActionCreators(actionCreators, dispatch))(DeleteRoute);
render() {
return (
<div>
<h2>Routes</h2>
<p>Routes define how items from CSS get imported into Rally. Use routes to connect a Rally project to a set of criteria in CSS.</p>
<div>
<AddRoute isOpen={this.props.showAddRoute} toggle={this.toggleAddRoute} />
<DeleteRoute error={this.props.deleteRouteError} success={this.props.deleteRouteSuccess} isOpen={this.props.showDeleteRoute} route={this.props.selectedRoute} toggle={this.toggleDeleteRoute} />
<DataTable
actions={[
{ Click: this.toggleAddRoute, Color: 'green', Icon: 'MdAdd', ToolTip: "Add new route" },
{ Click: this.toggleEditRoute, Color: 'orange', Icon: 'MdEdit', ToolTip: "Edit route", RowAction: true },
{ Click: this.toggleDeleteRoute, Color: 'red', Icon: 'MdRemove', ToolTip: "Delete route", RowAction: true },
]}
columns={[
{ Title: "Platform", Field: "CSSPlatform" },
{ Title: "Product", Field: "CSSProduct" },
{ Title: "SubProduct", Field: "CSSSubProduct" },
{ Title: "ProdManager", Field: "ProdManager" },
{ Title: "ProgSupervisor", Field: "ProgSupervisor" },
{ Title: "Product Active?", Field: "CSSProductActive" },
{ Title: "SubProduct Active?", Field: "CSSSubProductActive" },
{ Title: "Rally Project", Field: "RallyProject" },
{ Title: "Rally Url", Field: "RallyUrl" }
]}
data={this.props.routes}
edit={this.editRoute}
isLoading={this.props.isLoading} />
</div>
</div>
);
I ended up adding a redux action to reset the success and error props, and then calling that when the modal is closed. I think this is in line with correct redux architecture, but I'm open to better solutions if anyone has them.
class DeleteRoute extends React.Component {
constructor(props) {
super(props);
this.deleteRoute = this.deleteRoute.bind(this);
this.toggle = this.toggle.bind(this);
}
deleteRoute() {
this.props.deleteRoute(this.props.route);
}
toggle() {
if (this.props.isOpen) {
// reset the error and success messages on close
this.props.initialize();
}
this.props.toggle();
}
render() {
var route = this.props.route || {};
return (
<div>
<Modal
isOpen={this.props.isOpen}
toggle={this.toggle}
>
<ModalHeader toggle={this.toggle}>Delete Route</ModalHeader>
<ModalBody>
{this.props.isLoading && <Spinner color="primary" />}
<Alert color="danger" isOpen={this.props.error}>{this.props.error}</Alert>
<Alert color="success" isOpen={this.props.success}>Deleted successfully</Alert>
<Form>
<Row form>
<Col>
<FormGroup>
<Label for="CssPlatform">Css Platform</Label>
<Input disabled name="CssPlatform" type="text" value={route.CSSPlatform} />
</FormGroup>
</Col>
<Col>
<FormGroup>
<Label for="ProdManager">Prod Manager</Label>
<Input disabled name="ProdManager" type="text" value={route.ProdManager} />
</FormGroup>
</Col>
</Row>
<Row form>
<Col>
<FormGroup>
<Label for="CssProduct">Css Product</Label>
<Input disabled name="CssProduct" type="text" value={route.CSSProduct} />
</FormGroup>
</Col>
<Col>
<FormGroup>
<Label for="ProgSupervisor">Prog Supervisor</Label>
<Input disabled name="ProgSupervisor" type="text" value={route.ProgSupervisor} />
</FormGroup>
</Col>
</Row>
<Row form>
<Col>
<FormGroup>
<Label for="CssSubProduct">Css SubProduct</Label>
<Input disabled name="CssSubProduct" type="text" value={route.CSSSubProduct} />
</FormGroup>
</Col>
<Col>
<FormGroup>
<Label for="RallyProject">Rally Project</Label>
<Input disabled name="RallyProject" type="text" value={route.RallyProject} />
</FormGroup>
</Col>
</Row>
<Row form>
<Col>
<FormGroup check inline>
<Label check>
<Input disabled name="CssProductActive" type="checkbox" checked={route.CSSProductActive} />
Css Product Active
</Label>
</FormGroup>
</Col>
<Col>
<FormGroup check inline>
<Label check>
<Input disabled name="CssSubProductActive" type="checkbox" checked={route.CSSSubProductActive} />
Css SubProduct Active
</Label>
</FormGroup>
</Col>
</Row>
</Form>
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={this.deleteRoute}>Delete Route</Button>{' '}
<Button color="secondary" onClick={this.toggle}>Cancel</Button>
</ModalFooter>
</Modal>
</div>
);
}
}
export default connect(
state => state.deleteRouteReducer,
dispatch => bindActionCreators(actionCreators, dispatch))(DeleteRoute);
and the redux bits
import axios from 'axios';
// actions
const deleteRouteType = "DELETE_ROUTE";
const deleteRouteFailureType = "DELETE_ROUTE_FAILURE";
const deleteRouteSuccessType = "DELETE_ROUTE_SUCCESS";
const initializeType = "DELETE_ROUTE_INITIALIZE";
const initialState = { error: null, success: null };
// action creators
export const actionCreators = {
initialize: () => (dispatch) => {
dispatch({ type: initializeType });
},
deleteRoute: (route) => async (dispatch) => {
dispatch({ type: deleteRouteType });
axios
.delete(`api/route`, route)
.then(res => {
if (res.data.error) {
dispatch({ type: deleteRouteFailureType, payload: res.data.errorMessage });
}
else {
dispatch({ type: deleteRouteSuccessType, payload: res.data.data });
}
})
.catch(err => {
dispatch({ type: deleteRouteFailureType, payload: err.message });
});
}
};
// reducers
export const reducer = (state, action) => {
state = state || initialState;
switch (action.type) {
case initializeType:
return {
...state,
error: null,
isLoading: false,
success: false
};
case deleteRouteType:
return {
...state,
error: null,
isLoading: true,
success: false
};
case deleteRouteFailureType:
return {
...state,
error: action.payload,
isLoading: false,
success: false
};
case deleteRouteSuccessType:
return {
...state,
error: null,
isLoading: false,
success: true
};
default:
return state;
}
};
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