diff --git a/src/components/fields/ObjectField.js b/src/components/fields/ObjectField.js
index 4b7edb41f3..982aa3aaff 100644
--- a/src/components/fields/ObjectField.js
+++ b/src/components/fields/ObjectField.js
@@ -7,6 +7,7 @@ import {
retrieveSchema,
getDefaultRegistry,
getUiOptions,
+ ADDITIONAL_PROPERTY_FLAG,
} from "../../utils";
function DefaultObjectFieldTemplate(props) {
@@ -79,9 +80,24 @@ class ObjectField extends Component {
);
}
- onPropertyChange = name => {
+ onPropertyChange = (name, addedByAdditionalProperties = false) => {
return (value, errorSchema) => {
- const newFormData = { ...this.props.formData, [name]: value };
+ let newFormData;
+ //section below sets zero value of input field to empty string
+ //instead of undefined, so that value input in additionalProperties
+ //doesn't disappear when emptied
+ if (!value && addedByAdditionalProperties) {
+ newFormData = {
+ ...this.props.formData,
+ [name]: "",
+ };
+ } else {
+ newFormData = {
+ ...this.props.formData,
+ [name]: value,
+ };
+ }
+
this.props.onChange(
newFormData,
errorSchema &&
@@ -93,6 +109,16 @@ class ObjectField extends Component {
};
};
+ onDropIndexClick = key => {
+ return event => {
+ event.preventDefault();
+ const { onChange, formData } = this.props;
+ const copiedFormData = { ...formData };
+ delete copiedFormData[key];
+ onChange(copiedFormData);
+ };
+ };
+
getAvailableKey = (preferredKey, formData) => {
var index = 0;
var newKey = preferredKey;
@@ -176,7 +202,6 @@ class ObjectField extends Component {
const title = schema.title === undefined ? name : schema.title;
const description = uiSchema["ui:description"] || schema.description;
let orderedProperties;
-
try {
const properties = Object.keys(schema.properties);
orderedProperties = orderProperties(properties, uiSchema["ui:order"]);
@@ -200,6 +225,9 @@ class ObjectField extends Component {
TitleField,
DescriptionField,
properties: orderedProperties.map(name => {
+ const addedByAdditionalProperties = schema.properties[
+ name
+ ].hasOwnProperty(ADDITIONAL_PROPERTY_FLAG);
return {
content: (
),
name,
diff --git a/src/components/fields/SchemaField.js b/src/components/fields/SchemaField.js
index fd7ff9a795..1d10983c05 100644
--- a/src/components/fields/SchemaField.js
+++ b/src/components/fields/SchemaField.js
@@ -1,4 +1,5 @@
import { ADDITIONAL_PROPERTY_FLAG } from "../../utils";
+import IconButton from "../IconButton";
import React from "react";
import PropTypes from "prop-types";
@@ -107,7 +108,6 @@ function ErrorList(props) {
);
}
-
function DefaultTemplate(props) {
const {
id,
@@ -121,35 +121,57 @@ function DefaultTemplate(props) {
required,
displayLabel,
onKeyChange,
+ onDropIndexClick,
} = props;
if (hidden) {
return children;
}
+
const additional = props.schema.hasOwnProperty(ADDITIONAL_PROPERTY_FLAG);
const keyLabel = `${label} Key`;
return (
- {additional && (
-
-
-
+
+ {additional && (
+
+ )}
+
+
+ {displayLabel && }
+ {displayLabel && description ? description : null}
+ {children}
+ {errors}
+ {help}
+
+
+ {additional && (
+
+ )}
- )}
- {displayLabel &&
}
- {displayLabel && description ? description : null}
- {children}
- {errors}
- {help}
+
);
}
-
if (process.env.NODE_ENV !== "production") {
DefaultTemplate.propTypes = {
id: PropTypes.string,
@@ -186,6 +208,7 @@ function SchemaFieldRender(props) {
idPrefix,
name,
onKeyChange,
+ onDropIndexClick,
required,
registry = getDefaultRegistry(),
} = props;
@@ -285,6 +308,7 @@ function SchemaFieldRender(props) {
label,
hidden,
onKeyChange,
+ onDropIndexClick,
required,
disabled,
readonly,
diff --git a/src/components/fields/StringField.js b/src/components/fields/StringField.js
index 91fcf6911e..6ef3f3cbff 100644
--- a/src/components/fields/StringField.js
+++ b/src/components/fields/StringField.js
@@ -34,7 +34,6 @@ function StringField(props) {
uiSchema
);
const Widget = getWidget(schema, widget, widgets);
-
return (
{
ArrayFieldTemplate,
});
- expect(node.querySelectorAll(".field-array div")).to.have.length.of(3);
+ expect(node.querySelectorAll(".field-array div")).to.have.length.of(6);
});
});
diff --git a/test/ArrayField_test.js b/test/ArrayField_test.js
index 633c57347c..40e7f90b3a 100644
--- a/test/ArrayField_test.js
+++ b/test/ArrayField_test.js
@@ -24,7 +24,8 @@ describe("ArrayField", () => {
const { node } = createFormComponent({ schema: { type: "array" } });
expect(
- node.querySelector(".field-array > .unsupported-field").textContent
+ node.querySelector(".field-array > div > div > .unsupported-field")
+ .textContent
).to.contain("Missing items definition");
});
});
diff --git a/test/ObjectField_test.js b/test/ObjectField_test.js
index a0554e4b5f..b546ba55bf 100644
--- a/test/ObjectField_test.js
+++ b/test/ObjectField_test.js
@@ -197,7 +197,7 @@ describe("ObjectField", () => {
},
});
const labels = [].map.call(
- node.querySelectorAll(".field > label"),
+ node.querySelectorAll(".field > div > div > label"),
l => l.textContent
);
@@ -212,7 +212,7 @@ describe("ObjectField", () => {
},
});
const labels = [].map.call(
- node.querySelectorAll(".field > label"),
+ node.querySelectorAll(".field > div > div> label"),
l => l.textContent
);
@@ -277,7 +277,7 @@ describe("ObjectField", () => {
},
});
const labels = [].map.call(
- node.querySelectorAll(".field > label"),
+ node.querySelectorAll(".field > div > div > label"),
l => l.textContent
);
@@ -310,7 +310,7 @@ describe("ObjectField", () => {
},
});
const labels = [].map.call(
- node.querySelectorAll(".field > label"),
+ node.querySelectorAll(".field > div > div > label"),
l => l.textContent
);
@@ -678,5 +678,62 @@ describe("ObjectField", () => {
expect(node.querySelector(".object-property-expand button")).to.be.null;
});
+
+ it("should not have delete button if expand button has not been clicked", () => {
+ const { node } = createFormComponent({ schema });
+
+ expect(node.querySelector(".form-group > .btn-danger")).eql(null);
+ });
+
+ it("should have delete button if expand button has been clicked", () => {
+ const { node } = createFormComponent({
+ schema,
+ });
+
+ expect(
+ node.querySelector(".form-group > .row > .col-xs-2 .btn-danger")
+ ).eql(null);
+
+ Simulate.click(node.querySelector(".object-property-expand button"));
+
+ expect(node.querySelector(".form-group > .row > .col-xs-2 > .btn-danger"))
+ .to.not.be.null;
+ });
+
+ it("delete button should delete key-value pair", () => {
+ const { node } = createFormComponent({
+ schema,
+ formData: { first: 1 },
+ });
+ expect(node.querySelector("#root_first-key").value).to.eql("first");
+ Simulate.click(
+ node.querySelector(".form-group > .row > .col-xs-2 > .btn-danger")
+ );
+ expect(node.querySelector("#root_first-key")).to.not.exist;
+ });
+
+ it("delete button should delete correct pair", () => {
+ const { node } = createFormComponent({
+ schema,
+ formData: { first: 1, second: 2, third: 3 },
+ });
+ const selector = ".form-group > .row > .col-xs-2 > .btn-danger";
+ expect(node.querySelectorAll(selector).length).to.eql(3);
+ Simulate.click(node.querySelectorAll(selector)[1]);
+ expect(node.querySelector("#root_second-key")).to.not.exist;
+ expect(node.querySelectorAll(selector).length).to.eql(2);
+ });
+
+ it("deleting content of value input should not delete pair", () => {
+ const { comp, node } = createFormComponent({
+ schema,
+ formData: { first: 1 },
+ });
+
+ Simulate.change(node.querySelector("#root_first"), {
+ target: { value: "" },
+ });
+ expect(comp.state.formData["first"]).eql("");
+ });
});
});
diff --git a/test/SchemaField_test.js b/test/SchemaField_test.js
index fa503d767e..504e722ce8 100644
--- a/test/SchemaField_test.js
+++ b/test/SchemaField_test.js
@@ -313,7 +313,7 @@ describe("SchemaField", () => {
submit(node);
const matches = node.querySelectorAll(
- "form > .form-group > div > .error-detail .text-danger"
+ "form > .form-group > div > div > div > .error-detail .text-danger"
);
expect(matches).to.have.length.of(1);
expect(matches[0].textContent).to.eql("container");