Skip to content

Commit 74c6ec0

Browse files
jbalbonin1k0
authored andcommitted
Add transform hook for changing errors from json schema validation (rjsf-team#432)
1 parent 8c4707a commit 74c6ec0

File tree

6 files changed

+87
-6
lines changed

6 files changed

+87
-6
lines changed

README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ A [live playground](https://mozilla-services.github.io/react-jsonschema-form/) i
6666
- [Form data validation](#form-data-validation)
6767
- [Live validation](#live-validation)
6868
- [Custom validation](#custom-validation)
69+
- [Custom error messages](#custom-error-messages)
6970
- [Error List Display](#error-list-display)
7071
- [Styling your forms](#styling-your-forms)
7172
- [Schema definitions and references](#schema-definitions-and-references)
@@ -1170,6 +1171,36 @@ render((
11701171
> received as second argument.
11711172
> - The `validate()` function is called **after** the JSON schema validation.
11721173
1174+
### Custom error messages
1175+
1176+
Validation error messages are provided by the JSON Schema validation by default. If you need to change these messages or make any other modifications to the errors from the JSON Schema validation, you can define a transform function that receives the list of JSON Schema errors and returns a new list.
1177+
1178+
```js
1179+
function transformErrors(errors) {
1180+
return errors.map(error => {
1181+
if (error.name === "pattern") {
1182+
error.message = "Only digits are allowed"
1183+
}
1184+
return error;
1185+
});
1186+
}
1187+
1188+
const schema = {
1189+
type: "object",
1190+
properties: {
1191+
onlyNumbersString: {type: "string", pattern: "\d*"},
1192+
}
1193+
};
1194+
1195+
render((
1196+
<Form schema={schema}
1197+
transformErrors={transformErrors} />
1198+
), document.getElementById("app"));
1199+
```
1200+
1201+
> Notes:
1202+
> - The `transformErrors()` function must return the list of errors. Modifying the list in place without returning it will result in an error.
1203+
11731204
### Error List Display
11741205
11751206
To disable rendering of the error list at the top of the form, you can set the `showErrorList` prop to `false`. Doing so will still validate the form, but only the inline display will show.

playground/app.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,8 @@ class App extends Component {
317317
validate,
318318
theme,
319319
editor,
320-
ArrayFieldTemplate
320+
ArrayFieldTemplate,
321+
transformErrors
321322
} = this.state;
322323

323324
return (
@@ -363,6 +364,7 @@ class App extends Component {
363364
onChange={this.onFormDataChange}
364365
fields={{geo: GeoPosition}}
365366
validate={validate}
367+
transformErrors={transformErrors}
366368
onError={log("errors")} />}
367369
</div>
368370
</div>

playground/samples/validation.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@ function validate({pass1, pass2}, errors) {
55
return errors;
66
}
77

8+
function transformErrors(errors) {
9+
return errors.map(error => {
10+
if (error.name === "minimum" && error.property === "instance.age") {
11+
return Object.assign({}, error, {
12+
message: "You need to be 18 because of some legal thing"
13+
});
14+
}
15+
return error;
16+
});
17+
}
18+
819
module.exports = {
920
schema: {
1021
title: "Custom validation",
@@ -21,12 +32,18 @@ module.exports = {
2132
type: "string",
2233
minLength: 3
2334
},
35+
age: {
36+
title: "Age",
37+
type: "number",
38+
minimum: 18
39+
}
2440
}
2541
},
2642
uiSchema: {
2743
pass1: {"ui:widget": "password"},
2844
pass2: {"ui:widget": "password"},
2945
},
3046
formData: {},
31-
validate
47+
validate,
48+
transformErrors
3249
};

src/components/Form.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ export default class Form extends Component {
6060
}
6161

6262
validate(formData, schema) {
63-
const {validate} = this.props;
64-
return validateFormData(formData, schema || this.props.schema, validate);
63+
const {validate, transformErrors} = this.props;
64+
return validateFormData(formData, schema || this.props.schema, validate, transformErrors);
6565
}
6666

6767
renderErrors() {
@@ -202,6 +202,8 @@ if (process.env.NODE_ENV !== "production") {
202202
acceptcharset: PropTypes.string,
203203
noValidate: PropTypes.bool,
204204
liveValidate: PropTypes.bool,
205+
validate: PropTypes.func,
206+
transformErrors: PropTypes.func,
205207
safeRenderCompletion: PropTypes.bool,
206208
formContext: PropTypes.object,
207209
};

src/validate.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,11 @@ function unwrapErrorHandler(errorHandler) {
9696
* function, which receives the form data and an `errorHandler` object that
9797
* will be used to add custom validation errors for each field.
9898
*/
99-
export default function validateFormData(formData, schema, customValidate) {
100-
const {errors} = jsonValidate(formData, schema);
99+
export default function validateFormData(formData, schema, customValidate, transformErrors) {
100+
let {errors} = jsonValidate(formData, schema);
101+
if (typeof transformErrors === "function") {
102+
errors = transformErrors(errors);
103+
}
101104
const errorSchema = toErrorSchema(errors);
102105

103106
if (typeof customValidate !== "function") {

test/validate_test.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,32 @@ describe("Validation", () => {
9494
]);
9595
});
9696
});
97+
98+
describe("transformErrors", () => {
99+
const illFormedKey = "bar.'\"[]()=+*&^%$#@!";
100+
const schema = {
101+
type: "object",
102+
properties: {foo: {type: "string"}, [illFormedKey]: {type: "string"}}
103+
};
104+
const newErrorMessage = "Better error message";
105+
const transformErrors = (errors) => {
106+
return [
107+
Object.assign({}, errors[0], {message: newErrorMessage})
108+
];
109+
};
110+
111+
let errors;
112+
113+
beforeEach(() => {
114+
const result = validateFormData({foo: 42, [illFormedKey]: 41}, schema, undefined, transformErrors);
115+
errors = result.errors;
116+
});
117+
118+
it("should use transformErrors function", () => {
119+
expect(errors).not.to.be.empty;
120+
expect(errors[0].message).to.equal(newErrorMessage);
121+
});
122+
});
97123
});
98124

99125
describe("Form integration", () => {

0 commit comments

Comments
 (0)