Skip to content

Commit e27947f

Browse files
Lilyedgarmueller
Lily
authored andcommitted
[react] Add onChange props to React forms (#1448)
Add `onChange` property to `JsonForms` component. Fixes #1271
1 parent 8dd46ee commit e27947f

File tree

2 files changed

+102
-7
lines changed

2 files changed

+102
-7
lines changed

packages/react/src/JsonForms.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
*/
2525
import isEqual from 'lodash/isEqual';
2626
import maxBy from 'lodash/maxBy';
27-
import React from 'react';
27+
import React, { useEffect } from 'react';
2828
import AJV from 'ajv';
2929
import RefParser from 'json-schema-ref-parser';
3030
import { UnknownRenderer } from './UnknownRenderer';
@@ -38,6 +38,7 @@ import {
3838
OwnPropsOfJsonFormsRenderer,
3939
removeId,
4040
UISchemaElement,
41+
JsonFormsCore
4142
} from '@jsonforms/core';
4243
import { ctxToJsonFormsDispatchProps, JsonFormsStateProvider, useJsonForms } from './JsonFormsContext';
4344

@@ -48,6 +49,10 @@ interface JsonFormsRendererState {
4849
resolvedSchema: JsonSchema;
4950
}
5051

52+
interface JsonFormsReactProps {
53+
onChange?(state: Pick<JsonFormsCore, 'data' | 'errors'>): void;
54+
}
55+
5156
const hasRefs = (schema: JsonSchema): boolean => {
5257
if (schema !== undefined) {
5358
return Object.keys(findRefs(schema)).length > 0;
@@ -156,9 +161,14 @@ export class JsonFormsDispatchRenderer extends ResolvedJsonFormsDispatchRenderer
156161
}
157162
}
158163

159-
export const JsonFormsDispatch = (props: OwnPropsOfJsonFormsRenderer) => {
164+
export const JsonFormsDispatch = (props: OwnPropsOfJsonFormsRenderer & JsonFormsReactProps) => {
160165
const ctx = useJsonForms();
161166
const { refResolver } = ctxToJsonFormsDispatchProps(ctx, props);
167+
const {data, errors} = ctx.core
168+
useEffect(() => {
169+
props.onChange && props.onChange({ data, errors });
170+
}, [data, errors]);
171+
162172
return (
163173
<JsonFormsDispatchRenderer
164174
schema={props.schema || ctx.core.schema}
@@ -180,8 +190,8 @@ export interface JsonFormsInitStateProps {
180190
refParserOptions?: RefParser.Options;
181191
}
182192

183-
export const JsonForms = (props: JsonFormsInitStateProps) => {
184-
const { ajv, data, schema, uischema, renderers, refParserOptions } = props;
193+
export const JsonForms = (props: JsonFormsInitStateProps & JsonFormsReactProps) => {
194+
const { ajv, data, schema, uischema, renderers, refParserOptions, onChange } = props;
185195
return (
186196
<JsonFormsStateProvider
187197
initState={{
@@ -196,7 +206,7 @@ export const JsonForms = (props: JsonFormsInitStateProps) => {
196206
renderers
197207
}}
198208
>
199-
<JsonFormsDispatch />
209+
<JsonFormsDispatch onChange={onChange}/>
200210
</JsonFormsStateProvider>
201211
);
202212
};

packages/react/test/renderers/JsonForms.test.tsx

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,15 @@ import RefParser from 'json-schema-ref-parser';
4545
import { StatelessRenderer } from '../../src/Renderer';
4646

4747
import Adapter from 'enzyme-adapter-react-16';
48-
import { JsonFormsDispatchRenderer, JsonFormsDispatch, JsonForms } from '../../src/JsonForms';
48+
import {
49+
JsonFormsDispatchRenderer,
50+
JsonFormsDispatch,
51+
JsonForms
52+
} from '../../src/JsonForms';
4953
import {
5054
JsonFormsReduxContext,
5155
useJsonForms,
56+
withJsonFormsControlProps,
5257
JsonFormsStateProvider
5358
} from '../../src/JsonFormsContext';
5459

@@ -242,7 +247,7 @@ test('ids should be unique within the same form', () => {
242247
<JsonFormsReduxContext>
243248
<JsonFormsDispatch uischema={uischema2} schema={fixture.schema} />
244249
</JsonFormsReduxContext>
245-
</Provider>,
250+
</Provider>
246251
);
247252

248253
expect(ids.indexOf('#/properties/foo') > -1).toBeTruthy();
@@ -505,3 +510,83 @@ test('JsonForms should create a JsonFormsStateProvider with initState props', ()
505510

506511
expect(jsonFormsStateProviderInitStateProp.renderers).toBe(renderers);
507512
});
513+
514+
test('JsonForms should call onChange handler with new data', () => {
515+
const onChangeHandler = jest.fn();
516+
const TestInputRenderer = withJsonFormsControlProps(props => (
517+
<input onChange={ev => props.handleChange('foo', ev.target.value)} />
518+
));
519+
520+
const renderers = [
521+
{
522+
tester: () => 10,
523+
renderer: TestInputRenderer
524+
}
525+
];
526+
const wrapper = mount(
527+
<JsonForms
528+
data={fixture.data}
529+
uischema={fixture.uischema}
530+
schema={fixture.schema}
531+
onChange={onChangeHandler}
532+
renderers={renderers}
533+
/>
534+
);
535+
536+
wrapper.find('input').simulate('change', {
537+
target: {
538+
value: 'Test Value'
539+
}
540+
});
541+
542+
const calls = onChangeHandler.mock.calls;
543+
const lastCallParameter = calls[calls.length - 1][0];
544+
expect(lastCallParameter.data).toEqual({ foo: 'Test Value' });
545+
expect(lastCallParameter.errors).toEqual([]);
546+
});
547+
548+
test('JsonForms should call onChange handler with errors', () => {
549+
const onChangeHandler = jest.fn();
550+
const TestInputRenderer = withJsonFormsControlProps(props => (
551+
<input onChange={ev => props.handleChange('foo', ev.target.value)} />
552+
));
553+
554+
const schema = {
555+
type: 'object',
556+
properties: {
557+
foo: {
558+
type: 'string',
559+
minLength: 5
560+
}
561+
},
562+
required: ['foo']
563+
};
564+
565+
const renderers = [
566+
{
567+
tester: () => 10,
568+
renderer: TestInputRenderer
569+
}
570+
];
571+
const wrapper = mount(
572+
<JsonForms
573+
data={fixture.data}
574+
uischema={fixture.uischema}
575+
schema={schema}
576+
onChange={onChangeHandler}
577+
renderers={renderers}
578+
/>
579+
);
580+
581+
wrapper.find('input').simulate('change', {
582+
target: {
583+
value: 'xyz'
584+
}
585+
});
586+
587+
const calls = onChangeHandler.mock.calls;
588+
const lastCallParameter = calls[calls.length - 1][0];
589+
expect(lastCallParameter.data).toEqual({ foo: 'xyz' });
590+
expect(lastCallParameter.errors.length).toEqual(1);
591+
expect(lastCallParameter.errors[0].keyword).toEqual('minLength');
592+
});

0 commit comments

Comments
 (0)