Skip to content

Commit

Permalink
Initial support for property & schema dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
mfulton26 committed Aug 6, 2017
1 parent b3d03fa commit 6fc5633
Show file tree
Hide file tree
Showing 9 changed files with 508 additions and 26 deletions.
4 changes: 4 additions & 0 deletions playground/samples/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import files from "./files";
import single from "./single";
import customArray from "./customArray";
import alternatives from "./alternatives";
import propertyDependencies from "./propertyDependencies";
import schemaDependencies from "./schemaDependencies";

export const samples = {
Simple: simple,
Expand All @@ -32,4 +34,6 @@ export const samples = {
Single: single,
"Custom Array": customArray,
Alternatives: alternatives,
"Property dependencies": propertyDependencies,
"Schema dependencies": schemaDependencies,
};
86 changes: 86 additions & 0 deletions playground/samples/propertyDependencies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
module.exports = {
schema: {
title: "Property dependencies",
description: "These samples are best viewed without live validation.",
type: "object",
properties: {
unidirectional: {
title: "Unidirectional",
src:
"https://spacetelescope.github.io/understanding-json-schema/reference/object.html#dependencies",
description:
"In the following example, whenever a `credit_card` property is provided, a `billing_address` property must also be present.",
type: "object",
properties: {
name: {
type: "string",
},
credit_card: {
type: "number",
},
billing_address: {
type: "string",
},
},
required: ["name"],
dependencies: {
credit_card: ["billing_address"],
},
},
bidirectional: {
title: "Bidirectional",
src:
"https://spacetelescope.github.io/understanding-json-schema/reference/object.html#dependencies",
description:
"Dependencies are not bidirectional, you can, of course, define the bidirectional dependencies explicitly.",
type: "object",
properties: {
name: {
type: "string",
},
credit_card: {
type: "number",
},
billing_address: {
type: "string",
},
},
required: ["name"],
dependencies: {
credit_card: ["billing_address"],
billing_address: ["credit_card"],
},
},
},
},
uiSchema: {
unidirectional: {
credit_card: {
"ui:help":
"If you enter anything here then `billing_address` will become required.",
},
billing_address: {
"ui:help":
"It’s okay to have a billing address without a credit card number.",
},
},
bidirectional: {
credit_card: {
"ui:help":
"If you enter anything here then `billing_address` will become required.",
},
billing_address: {
"ui:help":
"If you enter anything here then `credit_card` will become required.",
},
},
},
formData: {
unidirectional: {
name: "Tim",
},
bidirectional: {
name: "Jill",
},
},
};
171 changes: 171 additions & 0 deletions playground/samples/schemaDependencies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
module.exports = {
schema: {
title: "Schema dependencies",
description: "These samples are best viewed without live validation.",
type: "object",
properties: {
simple: {
src:
"https://spacetelescope.github.io/understanding-json-schema/reference/object.html#dependencies",
title: "Simple",
type: "object",
properties: {
name: {
type: "string",
},
credit_card: {
type: "number",
},
},
required: ["name"],
dependencies: {
credit_card: {
properties: {
billing_address: {
type: "string",
},
},
required: ["billing_address"],
},
},
},
conditional: {
title: "Conditional",
$ref: "#/definitions/person",
},
arrayOfConditionals: {
title: "Array of conditionals",
type: "array",
items: {
$ref: "#/definitions/person",
},
},
fixedArrayOfConditionals: {
title: "Fixed array of conditionals",
type: "array",
items: [
{
title: "Primary person",
$ref: "#/definitions/person",
},
],
additionalItems: {
title: "Additional person",
$ref: "#/definitions/person",
},
},
},
definitions: {
person: {
title: "Person",
type: "object",
properties: {
"Do you have any pets?": {
type: "string",
enum: ["No", "Yes: One", "Yes: More than one"],
default: "No",
},
},
required: ["Do you have any pets?"],
dependencies: {
"Do you have any pets?": {
oneOf: [
{
properties: {
"Do you have any pets?": {
enum: ["No"],
},
},
},
{
properties: {
"Do you have any pets?": {
enum: ["Yes: One"],
},
"How old is your pet?": {
type: "number",
},
},
required: ["How old is your pet?"],
},
{
properties: {
"Do you have any pets?": {
enum: ["Yes: More than one"],
},
"Do you want to get rid of any?": {
type: "boolean",
},
},
required: ["Do you want to get rid of any?"],
},
],
},
},
},
},
},
uiSchema: {
simple: {
credit_card: {
"ui:help":
"If you enter anything here then `billing_address` will be dynamically added to the form.",
},
},
conditional: {
"Do you want to get rid of any?": {
"ui:widget": "radio",
},
},
arrayOfConditionals: {
items: {
"Do you want to get rid of any?": {
"ui:widget": "radio",
},
},
},
fixedArrayOfConditionals: {
items: {
"Do you want to get rid of any?": {
"ui:widget": "radio",
},
},
additionalItems: {
"Do you want to get rid of any?": {
"ui:widget": "radio",
},
},
},
},
formData: {
simple: {
name: "Randy",
},
conditional: {
"Do you have any pets?": "No",
},
arrayOfConditionals: [
{
"Do you have any pets?": "Yes: One",
"How old is your pet?": 6,
},
{
"Do you have any pets?": "Yes: More than one",
"Do you want to get rid of any?": false,
},
],
fixedArrayOfConditionals: [
{
"Do you have any pets?": "No",
},
{
"Do you have any pets?": "Yes: One",
"How old is your pet?": 6,
},
{
"Do you have any pets?": "Yes: More than one",
"Do you want to get rid of any?": true,
},
],
},
};
3 changes: 2 additions & 1 deletion src/components/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ export default class Form extends Component {
const idSchema = toIdSchema(
schema,
uiSchema["ui:rootFieldId"],
definitions
definitions,
formData
);
return {
status: "initial",
Expand Down
36 changes: 28 additions & 8 deletions src/components/fields/ArrayField.js
Original file line number Diff line number Diff line change
Expand Up @@ -312,14 +312,24 @@ class ArrayField extends Component {
const arrayProps = {
canAdd: this.canAddItem(formData),
items: formData.map((item, index) => {
const itemSchema = retrieveSchema(
schema.items,
definitions,
formData[index]
);
const itemErrorSchema = errorSchema ? errorSchema[index] : undefined;
const itemIdPrefix = idSchema.$id + "_" + index;
const itemIdSchema = toIdSchema(itemsSchema, itemIdPrefix, definitions);
const itemIdSchema = toIdSchema(
itemSchema,
itemIdPrefix,
definitions,
formData[index]
);
return this.renderArrayFieldItem({
index,
canMoveUp: index > 0,
canMoveDown: index < formData.length - 1,
itemSchema: itemsSchema,
itemSchema: itemSchema,
itemIdSchema,
itemErrorSchema,
itemData: formData[index],
Expand Down Expand Up @@ -352,6 +362,7 @@ class ArrayField extends Component {
schema,
idSchema,
uiSchema,
formData,
disabled,
readonly,
autofocus,
Expand All @@ -360,7 +371,7 @@ class ArrayField extends Component {
} = this.props;
const items = this.props.formData;
const { widgets, definitions, formContext } = registry;
const itemsSchema = retrieveSchema(schema.items, definitions);
const itemsSchema = retrieveSchema(schema.items, definitions, formData);
const enumOptions = optionsList(itemsSchema);
const { widget = "select", ...options } = {
...getUiOptions(uiSchema),
Expand Down Expand Up @@ -423,6 +434,7 @@ class ArrayField extends Component {
const {
schema,
uiSchema,
formData,
errorSchema,
idSchema,
name,
Expand All @@ -437,11 +449,11 @@ class ArrayField extends Component {
let items = this.props.formData;
const { ArrayFieldTemplate, definitions, fields } = registry;
const { TitleField } = fields;
const itemSchemas = schema.items.map(item =>
retrieveSchema(item, definitions)
const itemSchemas = schema.items.map((item, index) =>
retrieveSchema(item, definitions, formData[index])
);
const additionalSchema = allowAdditionalItems(schema)
? retrieveSchema(schema.additionalItems, definitions)
? retrieveSchema(schema.additionalItems, definitions, formData)
: null;

if (!items || items.length < itemSchemas.length) {
Expand All @@ -456,11 +468,19 @@ class ArrayField extends Component {
className: "field field-array field-array-fixed-items",
disabled,
idSchema,
formData,
items: items.map((item, index) => {
const additional = index >= itemSchemas.length;
const itemSchema = additional ? additionalSchema : itemSchemas[index];
const itemSchema = additional
? retrieveSchema(schema.additionalItems, definitions, formData[index])
: itemSchemas[index];
const itemIdPrefix = idSchema.$id + "_" + index;
const itemIdSchema = toIdSchema(itemSchema, itemIdPrefix, definitions);
const itemIdSchema = toIdSchema(
itemSchema,
itemIdPrefix,
definitions,
formData[index]
);
const itemUiSchema = additional
? uiSchema.additionalItems || {}
: Array.isArray(uiSchema.items)
Expand Down
2 changes: 1 addition & 1 deletion src/components/fields/ObjectField.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class ObjectField extends Component {
} = this.props;
const { definitions, fields, formContext } = registry;
const { SchemaField, TitleField, DescriptionField } = fields;
const schema = retrieveSchema(this.props.schema, definitions);
const schema = retrieveSchema(this.props.schema, definitions, formData);
const title = schema.title === undefined ? name : schema.title;
let orderedProperties;
try {
Expand Down
3 changes: 2 additions & 1 deletion src/components/fields/SchemaField.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ DefaultTemplate.defaultProps = {
function SchemaFieldRender(props) {
const {
uiSchema,
formData,
errorSchema,
idSchema,
name,
Expand All @@ -158,7 +159,7 @@ function SchemaFieldRender(props) {
formContext,
FieldTemplate = DefaultTemplate,
} = registry;
const schema = retrieveSchema(props.schema, definitions);
const schema = retrieveSchema(props.schema, definitions, formData);
const FieldComponent = getFieldComponent(schema, uiSchema, fields);
const { DescriptionField } = fields;
const disabled = Boolean(props.disabled || uiSchema["ui:disabled"]);
Expand Down
Loading

0 comments on commit 6fc5633

Please sign in to comment.