RAFAEL DA SILVA
RAFAEL DA SILVA

Reputation: 119

Using Yup + Formik to validate Array of objects

I must validate an array of objects using Yup + Formik.

My current schema of Yup:

Yup.object().shape({
Enderecos: Yup.array()
  .of(
    Yup.object().shape({
      BairroId: Yup.number()
        .required('Campo obrigatório'),
      CtbEndCadMunicipio: Yup.number()
        .required('Campo obrigatório'),
      CtbEndTipo: Yup.number()
        .required('Campo obrigatório'),
      LograId: Yup.number()
        .required('Campo obrigatório'),
      MunId: Yup.number(),
      CtbEndComplemento: Yup.string()
        .min(defaultMinimumCharacters, `Minimo de ${defaultMinimumCharacters} caracteres`)
        .max(200, `Máximo de ${200} caracteres`)
        .required('Campo obrigatório'),
      CtbEndNumero: Yup.string()
        .min(defaultMinimumCharacters, `Minimo de ${defaultMinimumCharacters} caracteres`)
        .max(10, `Máximo de ${10} caracteres`)
        .required('Campo obrigatório'),
      CtbEndCep: Yup.string()
        .min(defaultMinimumCharacters, `Minimo de ${defaultMinimumCharacters} caracteres`)
        .max(8, `Máximo de ${8} caracteres`)
        .required('Campo obrigatório'),
    })
  )}),

I'm using formik along form HTML element, so I display the fields like this:

<div className='fv-row me-4 mb-7 w-100'>
        <label className='required fw-bold fs-6 mb-2'>CEP</label>
        <input
          placeholder='CEP'
          {...values?.getFieldProps('Enderecos[0].CtbEndCep')}
          type='text'
          maxLength={8}
          name='Enderecos[0].CtbEndCep'
          className={clsx(
            'form-control form-control-solid mb-3 mb-lg-0',
            { 'is-invalid': values?.touched.CtbEndCep && values?.errors.CtbEndCep },
            {
              'is-valid': values?.touched.CtbEndCep && !values?.errors.CtbEndCep,
            }
          )}
          onChange={(e: React.ChangeEvent<HTMLInputElement>) => values?.setFieldValue('Enderecos[0].CtbEndCep', e.target.value)}
        />
        {values?.touched.CtbEndCep && values?.errors.CtbEndCep && (
          <div className='fv-plugins-message-container'>
            <div className='fv-help-block'>
              <span role='alert'>{values?.errors.CtbEndCep}</span>
            </div>
          </div>
        )}
      </div>

The problem is if I want do touched a field in the array, like this values?.touched.Enderecos[0].CtbEndCep, I got error undefined, which make sense, since the touched object is empty when rendering the form for the first time.

My doubt is if it has a way to work like that and what can I do here? I want to see here the CSS/styles validations. The green, when the field is fuel up and red when there is something wrong with the value inputed into the field.

Upvotes: 1

Views: 2164

Answers (1)

RAFAEL DA SILVA
RAFAEL DA SILVA

Reputation: 119

I managed to solved my issue like this:

{values?.getFieldProps('Enderecos').value?.map((item: any, index: number) => (
    <div className='fv-row me-4 mb-7 w-100'>
                    <label className='required fw-bold fs-6 mb-2'>CEP</label>
                    <input
                      placeholder='CEP'
                      {...values?.getFieldProps('Enderecos[0].CtbEndCep')}
                      type='text'
                      maxLength={8}
                      name='Enderecos[0].CtbEndCep'
                      className={clsx(
                        'form-control form-control-solid mb-3 mb-lg-0',
                        { 'is-invalid': values?.touched.Enderecos?.[index]?.CtbEndCep && values?.errors.Enderecos?.[index]?.CtbEndCep },
                        {
                          'is-valid': values?.touched.Enderecos?.[index]?.CtbEndCep && !values?.errors.Enderecos?.[index]?.CtbEndCep,
                        }
                      )}
                      onChange={(e: React.ChangeEvent<HTMLInputElement>) => values?.setFieldValue('Enderecos[0].CtbEndCep', e.target.value)}
                      onBlur={() => onBlurBuscaCEP(0)}
                    />
                    {values?.touched.Enderecos?.[index]?.CtbEndCep && values?.errors.Enderecos?.[index]?.CtbEndCep && (
                      <div className='fv-plugins-message-container'>
                        <div className='fv-help-block'>
                          <span role='alert'>{values?.errors.Enderecos?.[index]?.CtbEndCep}</span>
                        </div>
                      </div>
                    )}
                  </div>
))}

I do a map in the values?.getFieldProps('Enderecos').value and use the index props from .map function as index of the current array and field I want validate, this worked well.

Upvotes: 1

Related Questions