jeffbski / joi-browser

joi validation bundled for the browser (deprecated) - use joi@16+
Other
271 stars 39 forks source link

Validating an Array of Objects Results in TypeError: "x" is read-only #37

Open yuschick opened 6 years ago

yuschick commented 6 years ago

Context

What are you trying to achieve or the steps to reproduce ?

I am trying to achieve validating an array containing a variable amount of objects.

Describe your issue here, include schemas and inputs you are validating if needed.

const otherLoansValidation = Joi.object().keys({
  id: Joi.number().min(0).required(),
  provider: Joi.string().invalid([Providers.DEFAULT]).required(),
  type: Joi.string().invalid([Types.DEFAULT]).required(),
  loanAmount: Joi.number().min(1).max(MAX_AMOUNT).required(),
  monthlyPayment: Joi.number().min(1).max(999999).max(Joi.ref('loanAmount')).required(),
  exists: Joi.bool().required()
});

loanFromOtherProviders: Joi.bool().required(),

allLoansFromOtherProviders: Joi.any().when('loanFromOtherProviders', {
  is: true,
  then: Joi.array().items(otherLoansValidation)
}),

Which result you had ?

I am currently implementing the allLoansFromOtherProviders form section. Prior to this, the form and validation worked as expected.

However, now, whenever there is an error in the allLoansFromOtherProviders section, Joi behaves as expected. But the issue comes when there are no errors in this section at which point Joi breaks with the following error:

TypeError: Cannot assign to read only property '0' of object '[object Array]'

The stack trace ends here: _class._checkItems node_modules/joi-browser/dist/joi-browser.js:8384

What did you expect ?

I expected no errors to be reported and the form to validate.

yuschick commented 6 years ago

In the event anybody sees this, I found the underlying issue.

I was using joi-browser in a Create React App application with Redux managing my state. After plenty of testing and workaround, I finally took a step back to see what the cause could be. I did this by hardcoding the dataset and schema from above and validating that and then trying to actual data and schema that was throwing the error.

What I found was the array I hardcoded would display like this in my console: arrayfrom

While the array in my state would log like this: arraystate

I don't fully understand what creates the difference but it seems as though the format (or maybe immutable state) of the array caused the issue of this post.

How I've fixed this is before calling my validate function I create a copy of my data and modify the array like this:

validate(data, schema, opts) {
  const datax = {
    ...data,
    loanBreakdowns: Array.from(data.loanBreakdowns)
  };
  ...
}

By doing that, I have a standard array in my data that is being validated and joi-browser works as expected.

If anybody could elaborate on this further, I would love to understand the 'why' of this happening and why this makes a difference. Hope this helps!

rocky-jaiswal commented 6 years ago

I think the Array is an instance of Seamless-Immutable (https://github.com/rtfeldman/seamless-immutable/blob/master/src/seamless-immutable.js) and it is not a standard JS array. You should be able to convert it to a standard array using - https://github.com/rtfeldman/seamless-immutable#asmutable