Repository: mozilla-services/react-jsonschema-form
Pull request #369 (2016-11-01 19:01:56)

asNumber: return undefined when value is empty string
It is currently impossible to clear the value of a number field that is not required because `asNumber` converts the empty string to `0`. This change adds a special case that returns `undefined`, so that the input can be cleared

### Checklist

* [x] **I'm adding or updating code**
  - [x] I've added and/or updated tests
  - [x] I've updated docs if needed


sjhewitt: @n1k0 - done, and I added the linter rule and fixed any errors
n1k0: @sjhewitt Fantastic, thank you so much :+1: 

Patch:
diff --git a/.eslintrc b/.eslintrc
index da6f88f79..f24ae972b 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -15,7 +15,8 @@
         "comma-dangle": [0],
         "no-unused-vars": [2, {"vars": "all", "args": "none"}],
         "no-console": [0],
-        "object-curly-spacing": [1, "never"]
+        "object-curly-spacing": [1, "never"],
+        "keyword-spacing": ["error"]
     },
     "env": {
         "es6": true,
diff --git a/src/components/fields/ObjectField.js b/src/components/fields/ObjectField.js
index 9aa4d1e65..17e3d506b 100644
--- a/src/components/fields/ObjectField.js
+++ b/src/components/fields/ObjectField.js
@@ -101,7 +101,7 @@ class ObjectField extends Component {
     try {
       const properties = Object.keys(schema.properties);
       orderedProperties = orderProperties(properties, uiSchema["ui:order"]);
-    } catch(err) {
+    } catch (err) {
       return (
         <div>
           <p className="config-error" style={{color: "red"}}>
diff --git a/src/utils.js b/src/utils.js
index 30c4b3e90..fff6df8bb 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -223,6 +223,9 @@ export function mergeObjects(obj1, obj2, concatArrays = false) {
 }
 
 export function asNumber(value) {
+  if (value === "") {
+    return undefined;
+  }
   if (/\.$/.test(value)) {
     // "3." can't really be considered a number even if it parses in js. The
     // user is most likely entering a float.
@@ -500,7 +503,7 @@ export function dataURItoBlob(dataURI) {
   // Built the Uint8Array Blob parameter from the base64 string.
   const binary = atob(splitted[1]);
   const array = [];
-  for(let i = 0; i < binary.length; i++) {
+  for (let i = 0; i < binary.length; i++) {
     array.push(binary.charCodeAt(i));
   }
   // Create the blob object


Test patch:
diff --git a/test/ArrayField_test.js b/test/ArrayField_test.js
index 636d5b11b..808e655df 100644
--- a/test/ArrayField_test.js
+++ b/test/ArrayField_test.js
@@ -189,7 +189,7 @@ describe("ArrayField", () => {
 
       try {
         Simulate.submit(node);
-      } catch(e) {
+      } catch (e) {
         // Silencing error thrown as failure is expected here
       }
 
diff --git a/test/FormContext_test.js b/test/FormContext_test.js
index 5de449c92..10608ada3 100644
--- a/test/FormContext_test.js
+++ b/test/FormContext_test.js
@@ -60,7 +60,7 @@ describe("FormContext", () => {
 
   it("should be passed to TemplateField", () => {
     function CustomTemplateField({formContext}) {
-      return <div id={formContext.foo} />;
+      return <div id={formContext.foo}/>;
     }
 
     const {node} = createFormComponent({
diff --git a/test/Form_test.js b/test/Form_test.js
index 414b1c79a..be0c0ce02 100644
--- a/test/Form_test.js
+++ b/test/Form_test.js
@@ -634,7 +634,7 @@ describe("Form", () => {
           function submit(node) {
             try {
               Simulate.submit(node);
-            } catch(err) {
+            } catch (err) {
               // Validation is expected to fail and call console.error, which is
               // stubbed to actually throw in createSandbox().
             }
diff --git a/test/utils_test.js b/test/utils_test.js
index 3ab24bdca..912b964c3 100644
--- a/test/utils_test.js
+++ b/test/utils_test.js
@@ -255,6 +255,10 @@ describe("utils", () => {
     it("should allow numbers with a 0 in the first decimal place", () => {
       expect(asNumber("3.07")).eql(3.07);
     });
+
+    it("should return undefined if the input is empty", () => {
+      expect(asNumber("")).eql(undefined);
+    });
   });
 
   describe("isMultiSelect()", () => {