How can I load my initialvalue in my form input?

Viewed 462

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))
  },
})

enter image description here

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>
  )
}
0 Answers
Related