I'm new to React Hook Forms, and I have everything working except showing the fields using useFieldArray on an edit screen where the data is passed in. For example, I have the following:
TicketForm.js
import { useForm, useFieldArray, Controller } from 'react-hook-form';
import {
CCard,
CCardHeader,
CCollapse,
CCardBody,
CRow,
CCol,
CSidebar,
CSpinner,
CForm,
CFormGroup,
CInputCheckbox,
CFormText,
CTextarea,
CInput,
CInputFile,
CLabel,
CButton,
CButtonToolbar,
CButtonGroup,
CSelect
} from '@coreui/react';
import CIcon from '@coreui/icons-react';
import { useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import Input from '../../base/forms/input';
import Select from '../../base/forms/select';
import TextArea from '../../base/forms/text_area';
import Checkbox from '../../base/forms/check_box';
import LineItems from './line_items';
import Attachments from './attachment_items';
const TicketHookForm = props => {
let ticket = props.ticket;
const ticketData = Object.keys(ticket).length ? {
defaultValues: {
line_items_attributes: [...ticket.line_items],
attachments_attributes: [...ticket.attachments]
}
} : {};
console.log('ticket data is', ticketData);
const { setValue, control, handleSubmit, watch } = useForm(ticketData);
const stores = useSelector(state => state.referenceData.stores);
const categories = useSelector(state => state.referenceData.categories);
const history = useHistory();
const formatReferenceData = (data, selectedId) => {
return data.map(item => <option key={item.id} value={item.id} selected={item.id === selectedId}>{item.name}</option>);
}
const submit = (data) => {
console.log('data', data);
props.onSubmit(data);
}
return (
<CRow>
<CCol xs={12}>
<CForm onSubmit={(e) => {
e.preventDefault();
handleSubmit(submit)()
}} method="post" encType="multipart/form-data">
<CFormGroup row>
<CCol xs={3}>
<CLabel htmlFor="line_items">Line Items</CLabel>
</CCol>
<CCol xs={9}>
<LineItems control={control} />
</CCol>
</CFormGroup>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>Additional Information</CCardHeader>
<CCardBody>
<CFormGroup row>
<CCol xs={3}>
<CLabel htmlFor="attachments">Attachments</CLabel>
</CCol>
<CCol xs={9}>
<Attachments control={control} setValue={setValue} />
</CCol>
</CFormGroup>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<CButton type="submit" color="primary"><CIcon name="cil-user" /> {props.ticketId ? 'Update' : 'Create'} Check Request</CButton>
<CButton type="reset" color="danger" onClick={() => history.goBack()}><CIcon name="cil-ban" /> Cancel</CButton>
</CCardHeader>
</CCard>
</CForm>
</CCol>
</CRow>
)
}
TicketHookForm.defaultProps = {
ticket: {}
}
export default TicketHookForm;
From the console.log above, I see that ticketData is being set properly. For example, I have this output:
ticket data is {
defaultValues:
attachments_attributes: [{…}]
line_items_attributes: [{id: 8, description: "333", store: "Holman Cadillac", store_id: 2, account: "1", …}]
}
}
If I logged out what control is, I also notice everything is empty:
control is {
fieldArrayDefaultValuesRef: {
current: {
attachments_attributes: [],
line_items_attributes: []
}
}
Then, I have this file LineItems.js
import { useFieldArray } from 'react-hook-form';
import {
CFormGroup,
CRow,
CLabel,
CButton,
CCol
} from '@coreui/react';
import Input from '../../base/forms/input';
import Select from '../../base/forms/select';
import { useSelector } from 'react-redux';
const LineItems = props => {
const { fields, append, prepend, remove, swap, move, insert } = useFieldArray({
control: props.control,
name: 'line_items_attributes'
});
console.log('fields are ', fields);
const stores = useSelector(state => state.referenceData.stores);
const formatStores = () => {
return stores.map(item => <option key={item.id} value={item.id}>{item.name}</option>);
}
return (
<section className="line-item">
{fields.map((item, index) => (
<div key={item.id}>
<CFormGroup row>
<CCol xs={4}>
<CLabel htmlFor="store">Store</CLabel>
<Select control={props.control} defaultValue={item.store_id} id="store-select" name={`line_items_attributes[${index}].store_id`} options={formatStores(stores)} control={props.control} />
</CCol>
<CCol xs={4}>
<CLabel htmlFor="description">Description</CLabel>
<Input control={props.control} defaultValue={item.description} id="description" name={`line_items_attributes[${index}].description`} />
</CCol>
<CCol xs={4}>
<CLabel htmlFor="control_1">Control 1</CLabel>
<Input control={props.control} defaultValue={item.control} id="control_1" name={`line_items_attributes[${index}].control`} />
</CCol>
</CFormGroup>
<CFormGroup row>
<CCol xs={4}>
<CLabel htmlFor="account">Account</CLabel>
<Input control={props.control} defaultValue={item.account} name={`line_items_attributes[${index}].account`} id="account" />
</CCol>
<CCol xs={4}>
<CLabel htmlFor="amount">Amount</CLabel>
<Input control={props.control} defaultValue={item.amount} type="number" id="amount" name={`line_items_attributes[${index}].amount`} />
</CCol>
<CCol xs={4}>
<CLabel htmlFor="control_2">Control 2</CLabel>
<Input control={props.control} defaultValue={item.control2} name={`line_items_attributes[${index}].control2`} id="control_2" />
</CCol>
</CFormGroup>
<CRow>
<CCol xs={12} className="text-right"><CButton color="danger" onClick={() => remove(index)}>Remove</CButton></CCol>
</CRow>
</div>
))}
<CButton color="primary" variant="outline" onClick={() => append({})}>Add Line</CButton>
</section>
)
}
export default LineItems;
Input.js
import {
CInput
} from '@coreui/react';
import { Controller } from 'react-hook-form';
const Input = (props) => {
return (
<Controller
control={props.control}
name={props.name}
defaultValue={props.defaultValue}
render={({field: { onChange, onBlur, value, ref } }) => {
return <CInput defaultValue={props.defaultValue} id={props.id} onChange={onChange} />
}}
/>
)
}
export default Input;
The problem is my console.log('fields are', fields) keeps telling me fields is []. I'm not understanding what I'm missing here. I'm passing the control that I set up with useForm to my <LineItems> component.
I have the key names of my defaultValues objects match the name of the useFieldArray configuration, yet fields keeps showing up empty. I'm hoping somebody can let me know what I'm missing.
Thank you!