I need to create a modify feature on a value. I have the input setup inside a modal but for some reason I can't seem to pass on the value to the initialValues.
My code starts with ActivityAreas
<Datatable
ref={this.datatable}
rows={this.props.activityAreas}
update={this.props.updateTable}
headers={[
{
key: "name",
title: () => t("entities.activityAreas.name"),
},
{
key: "action",
title: () => t("entities.activityAreas.action"),
render: (_, row) => (
<Flex>
<ClickableLink onClick={() => this.openModalDestroy(row)}>
{t("entities.activityAreas.destroy")}
</ClickableLink>
<ClickableLink onClick={() => this.openModalRename(row)}>
{t("entities.activityAreas.rename")}
</ClickableLink>
</Flex>
),
props: { align: "right" },
},
]}
type={ACTIVITY_AREAS}
/>
The line that says this.openModalRename(row)
contains the actual line object with name and id. openModalRename looks like this right now
openModalRename = (row) => {
let modalProps = this.modalProps;
modalProps.row=row;
this.props.setModal(RenameActivityArea, modalProps, { width: '500px' })
}
It sends the data to the RenameActivityArea page
That page looks like this:
const RenameActivityArea = ({
values,
handleSubmit,
handleChange,
isValid,
hideModal,
isSubmitting,
setFieldValue,
...props
}) => {
const input = (name, inputProps) => (
<Input
{...getFormInputProps(
{
handleSubmit,
handleChange,
values,
isValid,
...props,
},
name,
inputProps
)}
/>
);
return (
<Form onSubmit={handleSubmit}>
<Header.H2>{t("settings.activityAreas.modActivityAreas")}</Header.H2>
{input("name", { label: "activityAreas.ActivityAreaName" })}
<ButtonRow
flex="0 0 auto"
flow="row"
justify="flex-end"
padding="10px 0px"
>
<Button type="button" outline onClick={hideModal}>
Fermer
</Button>
<Button
loading={isSubmitting}
disabled={!isValid}
onClick={handleSubmit}
>
{t("entities.activityAreas.save")}
</Button>
</ButtonRow>
</Form>
);
};
const initialValues = {
name: "",
};
const mapState = ({ entities }) => ({
activity_area: entities.activity_area,
});
const mapDispatch = (dispatch) => ({
onSubmit: (activity_area) => dispatch(updateActivityAreas(activity_area)),
});
RenameActivityArea.propTypes = {
modalProps: PropTypes.shape(),
handleSubmit: PropTypes.func,
handleChange: PropTypes.func,
hideModal: PropTypes.func,
isSubmitting: PropTypes.bool,
handleBlur: PropTypes.func,
errors: PropTypes.shape(),
touched: PropTypes.shape(),
isValid: PropTypes.bool,
};
const FormWrapped = withForm({
mapPropsToValues: () => initialValues,
validateOnChange: false,
validateOnBlur: true,
validationSchema: schema,
afterSubmit: (values, formik) =>
formik.props.afterModalSubmit(values, formik),
})(RenameActivityArea);
const Connected = connect(mapState, mapDispatch)(FormWrapped);
export default Connected;
I can get the value inside the box if I do this:
<Input {...getFormInputProps({
handleSubmit,
handleChange,
values: props.row, // <- This gives the value
isValid,
...props,
}, name, inputProps)}
/>
But then for some reason, I can't seem to be allowed to modify the value inside the input. It's like if it was read only or something. I am not sure thats the right way of approaching this anyway.
EDIT
getFormInputProps
export const getFormInputProps = (formProps, name, { label = name.replace('Attributes', ''), ...props } = {}) => {
const error = browseObject(formProps.errors, name)
const isTouched = browseObject(formProps.touched, name)
return {
onChange: formProps.handleChange,
label: label && t(`entities.${label}`),
error,
name,
value: browseObject(formProps.values, name) || '',
onBlur: formProps.handleBlur,
touched: isTouched,
...props,
}
}
withForm
export default withForm({
mapPropsToValues,
validateOnChange: false,
validateOnBlur: true,
validationSchema: schema,
afterSubmit: (_, { props: { history } }, { payload: { user } }) => {
history.push(getRedirect(user))
},
})
By adding the value inside the input field i can see it inside the modal but I can't type or change it. The Input does not have any read-only restrictions but still does not allow typing. So I might not be doing this the right way.
It looks like it uses Formik https://formik.org/docs/overview
EDIT: The utils/form is the following. As you can see it uses Formik
import { withFormik } from 'formik'
import { debounce } from 'lodash'
import objectToFormData from 'object-to-formdata'
import * as yup from 'yup'
import API from '../config/api'
import t from './translate'
import { DEFAULT_TEXT_WRAP, DEFAULT_TEXT_WRAP_THRESHOLD } from '../config/constants'
yup.setLocale({
mixed: {
required: () => t('errors.fieldIsRequired'),
},
})
const DEFAULT = (afterSubmit = () => { }) => ({
handleSubmit: (values, formik) => {
formik.props.onSubmit(values).then((action) => {
formik.setSubmitting(false)
afterSubmit(values, formik, action)
})
},
})
export default ({
afterSubmit = (values, { props: { afterSubmit: after } }) => after && after(values),
...attrs
}) => withFormik(Object.assign({}, DEFAULT(afterSubmit), attrs))
export async function checkExists(url, params) {
const response = await fetch(API.getUrl(url, params), {
method: 'GET',
headers: API.headers(),
})
return response
}
export const asyncSelectProps = formProps => key => ({
onChange: (items) => {
formProps.setFieldValue(key, items.map(item => item.id), false)
if (!formProps.touched[key]) {
formProps.setFieldTouched(key, true, false)
}
formProps.setFieldError(key, (!items.length) ? t('errors.mustContainAtLeastOneItem') : undefined, false)
},
touched: formProps.touched[key],
error: formProps.errors[key],
})
/* eslint prefer-arrow-callback: 0 */
/* eslint func-names: 0 */
yup.addMethod(yup.string, 'asyncUnique', function (url, body, message) {
return this.test({
name: 'asyncUnique',
message,
test: debounce(async (value) => {
if (value && value.length > 0) {
const response = await checkExists(`/exists/${url}`, body(value))
const { exists } = await response.json()
return !exists
}
return true
}, 500),
})
})
export const browseObject = (object, path) => {
const parsePath = (path.constructor === String) ? path.split('.') : path
const [key, ...rest] = parsePath
if (object && object[key] !== undefined) {
const next = object[key]
return (rest.length > 0) ? browseObject(next, rest) : next
}
return null
}
export const getFormInputProps = (formProps, name, { label = name.replace('Attributes', ''), ...props } = {}) => {
const error = browseObject(formProps.errors, name)
const isTouched = browseObject(formProps.touched, name)
return {
onChange: formProps.handleChange,
label: label && t(`entities.${label}`),
error,
name,
value: browseObject(formProps.values, name) || '',
onBlur: formProps.handleBlur,
touched: isTouched,
...props,
}
}
export const preventPropagate = callback => (event) => {
event.stopPropagation()
callback(event)
}
export const extractFiles = (files, multiple = false) => (multiple ? files : files[0])
export const fileInputHandler = (formProps, name, multiple = false) => (event) => {
const file = extractFiles(event.target.files, multiple)
formProps.setFieldValue(name, file)
}
export const wrapText = (
text,
maximum = DEFAULT_TEXT_WRAP,
threshold = DEFAULT_TEXT_WRAP_THRESHOLD,
) => {
if ((text.length + threshold) > maximum) {
return `${text.slice(0, maximum)}...`
}
return text
}
export const toFormData = body => objectToFormData(body)
export const PHONE_NUMBER_REGEX = /^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$/
export const ZIP_CODE_REGEX = /^[A-Za-z]\d[A-Za-z][ -]?\d[A-Za-z]\d$/
EDIT: So instead of using the const to render my input, I used directly an input field and no I can edit. But why did the const cause the problem?
const RenameActivityArea = ({
values,
touched,
handleSubmit,
handleChange,
handleBlur,
isValid,
hideModal,
isSubmitting,
setFieldValue,
...props
}) => {
return (
<Form onSubmit={handleSubmit}>
<Header.H2>{t('settings.activityAreas.modActivityAreas')}</Header.H2>
<input
type="text"
onChange={handleChange}
onBlur={handleBlur}
value={values.name}
name="name"
/>
<ButtonRow flex="0 0 auto" flow="row" justify="flex-end" padding="10px 0px">
<Button type="button" outline onClick={hideModal}>Fermer</Button>
<Button loading={isSubmitting} disabled={!isValid} onClick={handleSubmit}>{t('entities.activityAreas.save')}</Button>
</ButtonRow>
</Form>
)
}
