Repository: mozilla-services/react-jsonschema-form
Pull request #442 (2017-01-18 01:42:05)

Enable Arrays to be marked as required, and fixes for strings marked as required
### Reasons for making this change
Reasons for making this change

New feature:

Enable the arrays to be marked as "required". Meaning that the user must select "at least one" option from the list.

This references the array part of ticket:
#411

It also refers to the string part of
#410 and #402

### Checklist

* [x] **I'm updating documentation**
  - [x] I've checked the rendering of the Markdown text I've added
  - [ ] If I'm adding a new section, I've updated the Table of Content
* [x] **I'm adding or updating code**
  - [ ] I've added and/or updated tests
  - [x] I've updated docs if needed
* [x] **I'm adding a new feature**
  - [x] I've updated the playground with an example use of the feature


crumblix: Nice pickup ... thank you!!! :)
crumblix: Thank you very much for the code review!  Much appreciated, I have no problem addressing a few nits :)


crumblix: Thanks again everyone for the feedback :)
I reverted the documentation and fixed the last nit to make the code cleaner and better.

I'll need to read up on minItems before making any changes to the documentation for that as I haven't used it before.

My plan is to try and get it working in the playground later before updating the documentation about it.

Either that or if someone who knows how it works already sends me a sentence I'll just include it.
crumblix: OK, so I've reverted the array changes, played around with minItems in the playground, and tried to make it clear how to achieve a similar (and more feature rich) result by using it in the documentation.

Thanks for pointing out minItems!

Patch:
diff --git a/README.md b/README.md
index 02a865bf1..bb9e53526 100644
--- a/README.md
+++ b/README.md
@@ -547,6 +547,23 @@ const uiSchema = {
 };
 ```
 
+Care should be taken when using the `required` property with arrays.  An empty array is sufficient to pass that validation check.  If you wish to ensure the user populates the array, you can specify the minimum number of items the user must select with the `minItems` property.
+
+Example:
+
+```js
+const schema = {
+  type: "array",
+  minItems: 2,
+  title: "A multiple choices list",
+  items: {
+    type: "string",
+    enum: ["foo", "bar", "fuzz", "qux"],
+  },
+  uniqueItems: true
+};
+```
+
 By default, checkboxes are stacked but if you prefer them inline:
 
 ```js
diff --git a/src/components/widgets/BaseInput.js b/src/components/widgets/BaseInput.js
index 4710a0c6e..32d59362e 100644
--- a/src/components/widgets/BaseInput.js
+++ b/src/components/widgets/BaseInput.js
@@ -8,13 +8,15 @@ function BaseInput(props) {
     value,
     readonly,
     autofocus,
-    onChange,
     options,  // eslint-disable-line
     schema,   // eslint-disable-line
     formContext,  // eslint-disable-line
     registry, // eslint-disable-line
     ...inputProps
   } = props;
+  const _onChange = ({target: {value}}) => {
+    return props.onChange(value === "" ? undefined : value);
+  };
   return (
     <input
       {...inputProps}
@@ -22,7 +24,7 @@ function BaseInput(props) {
       readOnly={readonly}
       autoFocus={autofocus}
       value={typeof value === "undefined" ? "" : value}
-      onChange={(event) => onChange(event.target.value)}/>
+      onChange={_onChange} />
   );
 }
 
diff --git a/src/components/widgets/TextareaWidget.js b/src/components/widgets/TextareaWidget.js
index d7be10236..38d665811 100644
--- a/src/components/widgets/TextareaWidget.js
+++ b/src/components/widgets/TextareaWidget.js
@@ -12,6 +12,9 @@ function TextareaWidget({
   autofocus,
   onChange
 }) {
+  const _onChange = ({target: {value}}) => {
+    return onChange(value === "" ? undefined : value);
+  };  
   return (
     <textarea
       id={id}
@@ -22,7 +25,7 @@ function TextareaWidget({
       disabled={disabled}
       readOnly={readonly}
       autoFocus={autofocus}
-      onChange={(event) => onChange(event.target.value)}/>
+      onChange={_onChange} />
   );
 }
 


Test patch:
diff --git a/test/StringField_test.js b/test/StringField_test.js
index e5451dd1f..4a84557ea 100644
--- a/test/StringField_test.js
+++ b/test/StringField_test.js
@@ -77,6 +77,18 @@ describe("StringField", () => {
       expect(comp.state.formData).eql("yo");
     });
 
+    it("should handle an empty string change event", () => {
+      const {comp, node} = createFormComponent({schema: {
+        type: "string",
+      }});
+
+      Simulate.change(node.querySelector("input"), {
+        target: {value: ""}
+      });
+
+      expect(comp.state.formData).eql(undefined);
+    });
+
     it("should fill field with data", () => {
       const {node} = createFormComponent({schema: {
         type: "string",
@@ -203,6 +215,20 @@ describe("StringField", () => {
     });
   });
 
+  describe("TextareaWidget", () => {
+    it("should handle an empty string change event", () => {
+      const {comp, node} = createFormComponent({schema: {
+        type: "string",
+      }});
+
+      Simulate.change(node.querySelector("input"), {
+        target: {value: ""}
+      });
+
+      expect(comp.state.formData).eql(undefined);
+    });
+  });
+
   describe("DateTimeWidget", () => {
     it("should render an datetime-local field", () => {
       const {node} = createFormComponent({schema: {