Skip to content

Commit

Permalink
Properly pass formContext to SchemaField (#3040)
Browse files Browse the repository at this point in the history
* Properly pass formContext to SchemaField
- Updated `ArrayField`, `MultiSchemaField`, `ObjectField` and `SchemaField` to pass `formContext` down the hierarchy properly
- Updated tests to validate `formContext` is properly passed to `SchemaField`
- Updated the `CHANGELOG.md` file with the fix mentioned

* Update packages/core/test/allOf_test.js
  • Loading branch information
heath-freenome authored Aug 25, 2022
1 parent 93669b7 commit 15c011d
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ should change the heading of the (upcoming) version to include a major version b
- **BREAKING CHANGE** Fix overriding core submit button className (https://github.com/rjsf-team/react-jsonschema-form/issues/2979)
- Fix `ui:field` with anyOf or oneOf no longer rendered twice (#2890)
- **BREAKING CHANGE** Fixed `anyOf` and `oneOf` getting incorrect, potentially duplicate ids when combined with array (https://github.com/rjsf-team/react-jsonschema-form/issues/2197)
- `formContext` is now passed properly to `SchemaField`, fixes (https://github.com/rjsf-team/react-jsonschema-form/issues/2394, https://github.com/rjsf-team/react-jsonschema-form/issues/2274)

## @rjsf/antd
- Fix esm build to use `@rollup/plugin-replace` to replace `antd/lib` and `rc-picker/lib` with `antd/es` and `rc-picker/es` respectively, fixing (https://github.com/rjsf-team/react-jsonschema-form/issues/2962)
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/components/fields/ArrayField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -802,6 +802,7 @@ class ArrayField<T = any, F = any> extends Component<
readonly,
uiSchema,
registry,
formContext,
} = this.props;
const {
fields: { SchemaField },
Expand All @@ -825,6 +826,7 @@ class ArrayField<T = any, F = any> extends Component<
schema={itemSchema}
uiSchema={itemUiSchema}
formData={itemData}
formContext={formContext}
errorSchema={itemErrorSchema}
idPrefix={idPrefix}
idSeparator={idSeparator}
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/components/fields/MultiSchemaField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ class AnyOfField<T = any, F = any> extends Component<
hideError = false,
errorSchema = {},
formData,
formContext,
idPrefix,
idSeparator,
idSchema,
Expand Down Expand Up @@ -199,6 +200,7 @@ class AnyOfField<T = any, F = any> extends Component<
value={selectedOption}
options={{ enumOptions }}
registry={registry}
formContext={formContext}
{...uiOptions}
label=""
/>
Expand All @@ -213,6 +215,7 @@ class AnyOfField<T = any, F = any> extends Component<
idPrefix={idPrefix}
idSeparator={idSeparator}
formData={formData}
formContext={formContext}
onChange={onChange}
onBlur={onBlur}
onFocus={onFocus}
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/components/fields/ObjectField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ class ObjectField<T = any, F = any> extends Component<
idPrefix={idPrefix}
idSeparator={idSeparator}
formData={get(formData, name)}
formContext={formContext}
wasPropertyKeyModified={this.state.wasPropertyKeyModified}
onKeyChange={this.onKeyChange(name)}
onChange={this.onPropertyChange(
Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/components/fields/SchemaField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ function SchemaFieldRender<T, F>(props: FieldProps<T, F>) {
hideError={hideError}
errorSchema={errorSchema}
formData={formData}
formContext={formContext}
idPrefix={idPrefix}
idSchema={idSchema}
idSeparator={idSeparator}
Expand Down Expand Up @@ -341,6 +342,7 @@ function SchemaFieldRender<T, F>(props: FieldProps<T, F>) {
hideError={hideError}
errorSchema={errorSchema}
formData={formData}
formContext={formContext}
idPrefix={idPrefix}
idSchema={idSchema}
idSeparator={idSeparator}
Expand Down
43 changes: 43 additions & 0 deletions packages/core/test/ArrayField_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Simulate } from "react-dom/test-utils";
import sinon from "sinon";

import { createFormComponent, createSandbox, submitForm } from "./test_utils";
import SchemaField from "../src/components/fields/SchemaField";

const ArrayKeyDataAttr = "data-rjsf-itemkey";
const ExposedArrayKeyTemplate = function (props) {
Expand Down Expand Up @@ -2177,4 +2178,46 @@ describe("ArrayField", () => {
expect(inputsNoError).to.have.length.of(0);
});
});
describe("FormContext gets passed", () => {
const schema = {
type: "array",
items: [
{
type: "string",
title: "Some text",
},
{
type: "number",
title: "A number",
},
],
};
it("should pass form context to schema field", () => {
const formContext = {
root: "root-id",
root_0: "root_0-id",
root_1: "root_1-id",
};
function CustomSchemaField(props) {
const { formContext, idSchema } = props;
return (
<>
<code id={formContext[idSchema.$id]}>Ha</code>
<SchemaField {...props} />
</>
);
}
const { node } = createFormComponent({
schema,
formContext,
fields: { SchemaField: CustomSchemaField },
});

const codeBlocks = node.querySelectorAll("code");
expect(codeBlocks).to.have.length(3);
Object.keys(formContext).forEach((key) => {
expect(node.querySelector(`code#${formContext[key]}`)).to.exist;
});
});
});
});
29 changes: 29 additions & 0 deletions packages/core/test/ObjectField_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { expect } from "chai";
import { Simulate } from "react-dom/test-utils";
import sinon from "sinon";

import SchemaField from "../src/components/fields/SchemaField";
import { createFormComponent, createSandbox, submitForm } from "./test_utils";

describe("ObjectField", () => {
Expand Down Expand Up @@ -190,6 +191,34 @@ describe("ObjectField", () => {
expect(node.querySelector("input[type=text]").id).eql("root_foo");
expect(node.querySelector("input[type=checkbox]").id).eql("root_bar");
});

it("should pass form context to schema field", () => {
const formContext = {
root: "root-id",
root_foo: "foo-id",
root_bar: "bar-id",
};
function CustomSchemaField(props) {
const { formContext, idSchema } = props;
return (
<>
<code id={formContext[idSchema.$id]}>Ha</code>
<SchemaField {...props} />
</>
);
}
const { node } = createFormComponent({
schema,
formContext,
fields: { SchemaField: CustomSchemaField },
});

const codeBlocks = node.querySelectorAll("code");
expect(codeBlocks).to.have.length(3);
Object.keys(formContext).forEach((key) => {
expect(node.querySelector(`code#${formContext[key]}`)).to.exist;
});
});
});

describe("fields ordering", () => {
Expand Down
34 changes: 34 additions & 0 deletions packages/core/test/allOf_test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { expect } from "chai";
import React from "react";

import { createFormComponent, createSandbox } from "./test_utils";
import SchemaField from "../src/components/fields/SchemaField";

describe("allOf", () => {
let sandbox;
Expand Down Expand Up @@ -46,4 +48,36 @@ describe("allOf", () => {

expect(node.querySelectorAll("input")).to.have.length.of(0);
});
it("should pass form context to schema field", () => {
const schema = {
type: "object",
properties: {
foo: {
allOf: [{ type: "string" }, { type: "boolean" }],
},
},
};
const formContext = { root: "root-id", root_foo: "foo-id" };
function CustomSchemaField(props) {
const { formContext, idSchema } = props;
return (
<>
<code id={formContext[idSchema.$id]}>Ha</code>
<SchemaField {...props} />
</>
);
}
const { node } = createFormComponent({
schema,
formData: { userId: "foobarbaz" },
formContext,
fields: { SchemaField: CustomSchemaField },
});

const codeBlocks = node.querySelectorAll("code");
expect(codeBlocks).to.have.length(2);
Object.keys(formContext).forEach((key) => {
expect(node.querySelector(`code#${formContext[key]}`)).to.exist;
});
});
});
41 changes: 41 additions & 0 deletions packages/core/test/oneOf_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Simulate } from "react-dom/test-utils";
import sinon from "sinon";

import { createFormComponent, createSandbox, setProps } from "./test_utils";
import SchemaField from "../src/components/fields/SchemaField";

describe("oneOf", () => {
let sandbox;
Expand Down Expand Up @@ -394,6 +395,46 @@ describe("oneOf", () => {
expect(node.querySelectorAll("#custom-oneof-field")).to.have.length(1);
});

it("should pass form context to schema field", () => {
const schema = {
type: "object",
properties: {
userId: {
oneOf: [
{
type: "number",
},
{
type: "string",
},
],
},
},
};
const formContext = { root: "root-id", root_userId: "userId-id" };
function CustomSchemaField(props) {
const { formContext, idSchema } = props;
return (
<>
<code id={formContext[idSchema.$id]}>Ha</code>
<SchemaField {...props} />
</>
);
}
const { node } = createFormComponent({
schema,
formData: { userId: "foobarbaz" },
formContext,
fields: { SchemaField: CustomSchemaField },
});

const codeBlocks = node.querySelectorAll("code");
expect(codeBlocks).to.have.length(3);
Object.keys(formContext).forEach((key) => {
expect(node.querySelector(`code#${formContext[key]}`)).to.exist;
});
});

it("should select the correct field when the form is rendered from existing data", () => {
const schema = {
type: "object",
Expand Down

0 comments on commit 15c011d

Please sign in to comment.