Skip to content

Commit e4378c2

Browse files
authored
Add idPrefix option (rjsf-team#883)
1 parent 17ed8ff commit e4378c2

File tree

14 files changed

+260
-47
lines changed

14 files changed

+260
-47
lines changed

README.md

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ A [live playground](https://mozilla-services.github.io/react-jsonschema-form/) i
2222
- [Form error event handler](#form-error-event-handler)
2323
- [Form data changes](#form-data-changes)
2424
- [Form field blur events](#form-field-blur-events)
25+
- [Form field focus events](#form-field-focus-events)
2526
- [Form customization](#form-customization)
2627
- [The uiSchema object](#the-uischema-object)
2728
- [Alternative widgets](#alternative-widgets)
@@ -42,7 +43,8 @@ A [live playground](https://mozilla-services.github.io/react-jsonschema-form/) i
4243
- [removable option](#removable-option)
4344
- [Custom CSS class names](#custom-css-class-names)
4445
- [Custom labels for enum fields](#custom-labels-for-enum-fields)
45-
- [Disabled enum fields](#disabled-attribute-for-enum-fields)
46+
- [Alternative JSON-Schema compliant approach](#alternative-json-schema-compliant-approach)
47+
- [Disabled attribute for enum fields](#disabled-attribute-for-enum-fields)
4648
- [Multiple choices list](#multiple-choices-list)
4749
- [Autogenerated widget ids](#autogenerated-widget-ids)
4850
- [Form action buttons](#form-action-buttons)
@@ -60,11 +62,12 @@ A [live playground](https://mozilla-services.github.io/react-jsonschema-form/) i
6062
- [Array Field Template](#array-field-template)
6163
- [Object Field Template](#object-field-template)
6264
- [Error List template](#error-list-template)
65+
- [Id prefix](#id-prefix)
6366
- [Custom widgets and fields](#custom-widgets-and-fields)
6467
- [Custom widget components](#custom-widget-components)
6568
- [Custom component registration](#custom-component-registration)
6669
- [Custom widget options](#custom-widget-options)
67-
- [Customizing widgets' text input](#customizing-widgets-text-input)
70+
- [Customizing widgets text input](#customizing-widgets-text-input)
6871
- [Custom field components](#custom-field-components)
6972
- [Field props](#field-props)
7073
- [The registry object](#the-registry-object)
@@ -84,19 +87,22 @@ A [live playground](https://mozilla-services.github.io/react-jsonschema-form/) i
8487
- [Styling your forms](#styling-your-forms)
8588
- [Schema definitions and references](#schema-definitions-and-references)
8689
- [Property dependencies](#property-dependencies)
87-
- [Unidirectional](#unidirectional)
88-
- [Bidirectional](#bidirectional)
90+
- [Unidirectional](#unidirectional)
91+
- [Bidirectional](#bidirectional)
8992
- [Schema dependencies](#schema-dependencies)
90-
- [Conditional](#conditional)
91-
- [Dynamic](#dynamic)
93+
- [Conditional](#conditional)
94+
- [Dynamic](#dynamic)
9295
- [JSON Schema supporting status](#json-schema-supporting-status)
9396
- [Tips and tricks](#tips-and-tricks)
9497
- [Contributing](#contributing)
9598
- [Coding style](#coding-style)
9699
- [Development server](#development-server)
97100
- [Tests](#tests)
98101
- [TDD](#tdd)
102+
- [Releasing](#releasing)
99103
- [FAQ](#faq)
104+
- [Q: Does rjsf support oneOf, anyOf, multiple types in an array, etc.?](#q-does-rjsf-support-oneof-anyof-multiple-types-in-an-array-etc)
105+
- [Q: Will react-jsonschema-form support Material, Ant-Design, Foundation, or [some other specific widget library or frontend style]?](#q-will-react-jsonschema-form-support-material-ant-design-foundation-or-some-other-specific-widget-library-or-frontend-style)
100106
- [License](#license)
101107

102108
---
@@ -1184,7 +1190,7 @@ render((
11841190
11851191
> Note: Since v0.41.0, the `ui:widget` object API, where a widget and options were specified with `"ui:widget": {component, options}` shape, is deprecated. It will be removed in a future release.
11861192
1187-
#### Customizing widgets' text input
1193+
#### Customizing widgets text input
11881194

11891195
All the widgets that render a text input use the `BaseInput` component internally. If you need to customize all text inputs without customizing all widgets individially, you can provide a `BaseInput` component in the `widgets` property of `Form` (see [Custom component registration](#custom-component-registration).
11901196

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,18 @@
88
"build:dist": "rimraf dist && cross-env NODE_ENV=production webpack --config webpack.config.dist.js --optimize-minimize",
99
"build:playground": "rimraf build && cross-env NODE_ENV=production webpack --config webpack.config.prod.js --optimize-minimize && cp playground/index.prod.html build/index.html",
1010
"cs-check": "prettier -l $npm_package_prettierOptions '{playground,src,test}/**/*.js'",
11-
"cs-format": "prettier $npm_package_prettierOptions '{playground,src,test}/**/*.js' --write",
11+
"cs-format": "prettier --jsx-bracket-same-line --trailing-comma es5 --use-tabs false --semi --tab-width 2 '{playground,src,test}/**/*.js' --write",
1212
"dist": "npm run build:lib && npm run build:dist",
1313
"lint": "eslint src test playground",
1414
"precommit": "lint-staged",
1515
"publish-to-gh-pages": "npm run build:playground && gh-pages --dist build/",
1616
"publish-to-npm": "npm run build:readme && npm run dist && npm publish",
17+
"preversion": "npm run build:playground && npm run dist && npm run build:readme && npm run cs-check && npm run lint",
1718
"start": "node devServer.js",
1819
"tdd": "cross-env NODE_ENV=test mocha --compilers js:babel-register --watch --require ./test/setup-jsdom.js test/**/*_test.js",
1920
"test": "cross-env NODE_ENV=test mocha --compilers js:babel-register --require ./test/setup-jsdom.js test/**/*_test.js"
2021
},
21-
"prettierOptions": "--jsx-bracket-same-line --trailing-comma es5 --semi",
22+
"prettierOptions": "--jsx-bracket-same-line --trailing-comma es5 --semi --tab-width 2",
2223
"lint-staged": {
2324
"{playground,src,test}/**/*.js": [
2425
"npm run lint",

src/components/Form.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ export default class Form extends Component {
175175
children,
176176
safeRenderCompletion,
177177
id,
178+
idPrefix,
178179
className,
179180
name,
180181
method,
@@ -209,6 +210,7 @@ export default class Form extends Component {
209210
uiSchema={uiSchema}
210211
errorSchema={errorSchema}
211212
idSchema={idSchema}
213+
idPrefix={idPrefix}
212214
formData={formData}
213215
onChange={this.onChange}
214216
onBlur={this.onBlur}

src/components/fields/ArrayField.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,10 @@ function DefaultArrayItem(props) {
6464
<div className="col-xs-3 array-item-toolbox">
6565
<div
6666
className="btn-group"
67-
style={{ display: "flex", justifyContent: "space-around" }}>
67+
style={{
68+
display: "flex",
69+
justifyContent: "space-around",
70+
}}>
6871
{(props.hasMoveUp || props.hasMoveDown) && (
6972
<IconBtn
7073
icon="arrow-up"

src/components/fields/ObjectField.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ class ObjectField extends Component {
7373
required,
7474
disabled,
7575
readonly,
76+
idPrefix,
7677
onBlur,
7778
onFocus,
7879
registry = getDefaultRegistry(),
@@ -117,6 +118,7 @@ class ObjectField extends Component {
117118
uiSchema={uiSchema[name]}
118119
errorSchema={errorSchema[name]}
119120
idSchema={idSchema[name]}
121+
idPrefix={idPrefix}
120122
formData={formData[name]}
121123
onChange={this.onPropertyChange(name)}
122124
onBlur={onBlur}

src/components/fields/SchemaField.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ import PropTypes from "prop-types";
44
import {
55
isMultiSelect,
66
retrieveSchema,
7+
toIdSchema,
78
getDefaultRegistry,
9+
mergeObjects,
810
getUiOptions,
911
isFilesArray,
1012
deepEquals,
@@ -153,7 +155,7 @@ function SchemaFieldRender(props) {
153155
uiSchema,
154156
formData,
155157
errorSchema,
156-
idSchema,
158+
idPrefix,
157159
name,
158160
required,
159161
registry = getDefaultRegistry(),
@@ -164,7 +166,12 @@ function SchemaFieldRender(props) {
164166
formContext,
165167
FieldTemplate = DefaultTemplate,
166168
} = registry;
169+
let idSchema = props.idSchema;
167170
const schema = retrieveSchema(props.schema, definitions, formData);
171+
idSchema = mergeObjects(
172+
toIdSchema(schema, null, definitions, formData, idPrefix),
173+
idSchema
174+
);
168175
const FieldComponent = getFieldComponent(schema, uiSchema, idSchema, fields);
169176
const { DescriptionField } = fields;
170177
const disabled = Boolean(props.disabled || uiSchema["ui:disabled"]);
@@ -199,6 +206,7 @@ function SchemaFieldRender(props) {
199206
const field = (
200207
<FieldComponent
201208
{...props}
209+
idSchema={idSchema}
202210
schema={schema}
203211
uiSchema={{ ...uiSchema, classNames: undefined }}
204212
disabled={disabled}

src/components/widgets/BaseInput.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ import PropTypes from "prop-types";
44
function BaseInput(props) {
55
// Note: since React 15.2.0 we can't forward unknown element attributes, so we
66
// exclude the "options" and "schema" ones here.
7+
if (!props.id) {
8+
console.log("No id for", props);
9+
throw new Error(`no id for props ${JSON.stringify(props)}`);
10+
}
711
const {
812
value,
913
readonly,

test/ArrayField_test.js

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,10 @@ describe("ArrayField", () => {
435435
},
436436
},
437437
};
438-
let form = createFormComponent({ schema: complexSchema, formData: {} });
438+
let form = createFormComponent({
439+
schema: complexSchema,
440+
formData: {},
441+
});
439442
let inputs = form.node.querySelectorAll("input[type=text]");
440443
expect(inputs[0].value).eql("Default name");
441444
expect(inputs[1].value).eql("Default name");
@@ -726,7 +729,10 @@ describe("ArrayField", () => {
726729
});
727730

728731
it("should handle a change event", () => {
729-
const { comp, node } = createFormComponent({ schema, uiSchema });
732+
const { comp, node } = createFormComponent({
733+
schema,
734+
uiSchema,
735+
});
730736

731737
Simulate.change(node.querySelectorAll("[type=checkbox]")[0], {
732738
target: { checked: true },
@@ -1058,7 +1064,10 @@ describe("ArrayField", () => {
10581064
});
10591065

10601066
it("should fill fields with data", () => {
1061-
const { node } = createFormComponent({ schema, formData: ["foo", 42] });
1067+
const { node } = createFormComponent({
1068+
schema,
1069+
formData: ["foo", 42],
1070+
});
10621071
const strInput = node.querySelector(
10631072
"fieldset .field-string input[type=text]"
10641073
);

test/Form_test.js

Lines changed: 103 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,85 @@ describe("Form", () => {
6868
});
6969
});
7070

71+
describe("Changing idPrefix", function() {
72+
it("should work with simple example", function() {
73+
const schema = {
74+
type: "object",
75+
title: "root object",
76+
required: ["foo"],
77+
properties: {
78+
count: {
79+
type: "number",
80+
},
81+
},
82+
};
83+
const comp = renderIntoDocument(<Form schema={schema} idPrefix="rjsf" />);
84+
const node = findDOMNode(comp);
85+
const inputs = node.querySelectorAll("input");
86+
const ids = [];
87+
for (var i = 0, len = inputs.length; i < len; i++) {
88+
const input = inputs[i];
89+
ids.push(input.getAttribute("id"));
90+
}
91+
expect(ids).to.eql(["rjsf_count"]);
92+
});
93+
94+
it("should work with oneOf", function() {
95+
const schema = {
96+
$schema: "http://json-schema.org/draft-06/schema#",
97+
type: "object",
98+
properties: {
99+
connector: {
100+
type: "string",
101+
enum: ["aws", "gcp"],
102+
title: "Provider",
103+
default: "aws",
104+
},
105+
},
106+
dependencies: {
107+
connector: {
108+
oneOf: [
109+
{
110+
type: "object",
111+
properties: {
112+
connector: {
113+
type: "string",
114+
enum: ["aws"],
115+
},
116+
key_aws: {
117+
type: "string",
118+
},
119+
},
120+
},
121+
{
122+
type: "object",
123+
properties: {
124+
connector: {
125+
type: "string",
126+
enum: ["gcp"],
127+
},
128+
key_gcp: {
129+
type: "string",
130+
},
131+
},
132+
},
133+
],
134+
},
135+
},
136+
};
137+
138+
const comp = renderIntoDocument(<Form schema={schema} idPrefix="rjsf" />);
139+
const node = findDOMNode(comp);
140+
const inputs = node.querySelectorAll("input");
141+
const ids = [];
142+
for (var i = 0, len = inputs.length; i < len; i++) {
143+
const input = inputs[i];
144+
ids.push(input.getAttribute("id"));
145+
}
146+
expect(ids).to.eql(["rjsf_key_aws"]);
147+
});
148+
});
149+
71150
describe("Custom field template", () => {
72151
const schema = {
73152
type: "object",
@@ -592,7 +671,11 @@ describe("Form", () => {
592671
foo: "",
593672
};
594673
const onChange = sandbox.spy();
595-
const { node } = createFormComponent({ schema, formData, onChange });
674+
const { node } = createFormComponent({
675+
schema,
676+
formData,
677+
onChange,
678+
});
596679

597680
Simulate.change(node.querySelector("[type=text]"), {
598681
target: { value: "new" },
@@ -835,7 +918,10 @@ describe("Form", () => {
835918
});
836919

837920
it("should denote the new error in the field", () => {
838-
const { node } = createFormComponent({ schema, liveValidate: true });
921+
const { node } = createFormComponent({
922+
schema,
923+
liveValidate: true,
924+
});
839925

840926
Simulate.change(node.querySelector("input[type=text]"), {
841927
target: { value: "short" },
@@ -1056,7 +1142,9 @@ describe("Form", () => {
10561142
const { comp } = createFormComponent(formProps);
10571143

10581144
expect(comp.state.errorSchema).eql({
1059-
1: { __errors: ["should NOT be shorter than 4 characters"] },
1145+
1: {
1146+
__errors: ["should NOT be shorter than 4 characters"],
1147+
},
10601148
});
10611149
});
10621150

@@ -1108,8 +1196,12 @@ describe("Form", () => {
11081196

11091197
expect(comp.state.errorSchema).eql({
11101198
level1: {
1111-
1: { __errors: ["should NOT be shorter than 4 characters"] },
1112-
3: { __errors: ["should NOT be shorter than 4 characters"] },
1199+
1: {
1200+
__errors: ["should NOT be shorter than 4 characters"],
1201+
},
1202+
3: {
1203+
__errors: ["should NOT be shorter than 4 characters"],
1204+
},
11131205
},
11141206
});
11151207
});
@@ -1158,10 +1250,14 @@ describe("Form", () => {
11581250
expect(comp.state.errorSchema).eql({
11591251
outer: {
11601252
0: {
1161-
1: { __errors: ["should NOT be shorter than 4 characters"] },
1253+
1: {
1254+
__errors: ["should NOT be shorter than 4 characters"],
1255+
},
11621256
},
11631257
1: {
1164-
0: { __errors: ["should NOT be shorter than 4 characters"] },
1258+
0: {
1259+
__errors: ["should NOT be shorter than 4 characters"],
1260+
},
11651261
},
11661262
},
11671263
});

test/NumberField_test.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,9 @@ describe("NumberField", () => {
5151
});
5252

5353
it("should default state value to undefined", () => {
54-
const { comp } = createFormComponent({ schema: { type: "number" } });
54+
const { comp } = createFormComponent({
55+
schema: { type: "number" },
56+
});
5557

5658
expect(comp.state.formData).eql(undefined);
5759
});

0 commit comments

Comments
 (0)