Develorem
Develorem

Reputation: 163

Redux Form Validation for FieldArray in TypeScript

I'm implementing a FieldArray for the first time from redux-form and the UI works fine (although there seems some general perf implication I haven't diagnosed yet). The idea is that you click an ADD button to add another "room" to the form, which is just a text field (ignore the button component, its a custom component)

The validation code however doesn't compile. It seems I'm clashing on types, and not sure the right way to do it in typescript. I'm using guidance from this example on how to do validation, but that example is pure javascript.

The error is:

Type '{ _error: string; }' is not assignable to type 'string | ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | undefined'.

Here's the method that renders the fieldarray:

const renderRoomNames = (fieldProps: WrappedFieldArrayProps<string>) => (
    <Grid container spacing={4}>
      {fieldProps.fields.map((name: string, index: number) => {
        console.log('room - name', name);
        return (
          <Grid item xs={12} key={`gridroom${index + 1}`}>

            <Field            
              name={`${name}`}
              type="text"
              label={"Room " + (index + 1)}
              placeholder={`Enter a name for this room`}
              component={ReduxFormTextField}       
              required={true}
              disabled={isSuccessful}
              fullWidth      
            />
     
          </Grid>
      )})}
      <Grid item xs={12}>
        <StandardButtonBase
          variant="contained"
          color="primary"
          startIcon={<AddIcon />}
          align="right"
          disableTooltip={true}
          round={true}
          onClick={() => fieldProps.fields.push('')}
          buttonText="Add Room"
        />
        {fieldProps.meta.submitFailed && fieldProps.meta.error && <span>{fieldProps.meta.error}</span>}
      </Grid>
    </Grid>
  )

return (
   <FieldArray name="roomNames" component={renderRoomNames} />
)

And the validation code:

export const requestVirtualClinicFormDataValidator = (
  model?: IModel
): FormErrors<IModel> => {
  const errors: FormErrors<IModel> = {};

  if (!model) {
    errors._error = 'SNIP';
    return errors;
  }

  // General room name errors checked first
  if (isEmpty(model.roomNames) || model.roomNames.length === 0) {
    errors.roomNames = 'You require at least one room '
  } else if (model.roomNames.some((x) => isEmpty(x))) {
    errors.roomNames = { _error: 'All room names must have a value' };
  } else {
    // Specific individual room name checks second
    const roomNameErrors:any[] = [];

    if (model.roomNames.length === 1 && isEmpty(model.roomNames[0])) {
      roomNameErrors[0] = { _error: 'You must provide a name for your room' };     
    } else {        
      for (let i=0; i < model.roomNames.length; i++) {
        const roomName = model.roomNames[i];
        const count = model.roomNames.filter(x => x.toLowerCase() === roomName.toLowerCase()).length;
        if (count > 1) {
          roomNameErrors[i] = { _error: 'All rooms must have a unique name' }
        }
      }
      
      if (roomNameErrors && roomNameErrors.length > 0) {
        errors.roomNames = roomNameErrors;
      }
    }
  }

  return errors;
};

The problem is at compilation. It doesn't like the _error: part, it wants a straight string.

However it also won't allow the line errors.roomNames = roomNameErrors; if leaving roomNameErrors as a string array. That instead results in this error:

Type 'string[]' is not assignable to type 'string | ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | undefined'.

It seems that even though 'roomNames' property on my model is a string array, the type definition for this wants react component or string only. How do I pass back validation failures for a given field within the field array, using typescript? The example linked earlier simply doesn't pass typescript typings as they are currently setup.

Using redux-form 8.2.

Upvotes: 0

Views: 1359

Answers (1)

Develorem
Develorem

Reputation: 163

I found that the type definitions were indeed wrong. By switching the errors from FormErrors to type Any, it all compiled, and actually worked. I will log an issue with the definitely typed repo to fix this.

Upvotes: 1

Related Questions