Repository: mozilla-services/react-jsonschema-form (js)

Issue:
Cannot enter decimal value for number type
__Steps to reproduce:__

1. Navigate to "Numbers" tab in [live demo](http://mozilla-services.github.io/react-jsonschema-form/)
2. Select and backspace Number field to clear it
3. Once reset to 0, attempt to enter "3.14"
4. Note that it is not possible

__Expected cause:__

When [change event occurs](https://github.com/mozilla-services/react-jsonschema-form/blob/daca36b57c8ceea1cb932b062847372b1848850d/src/components/fields/NumberField.js#L9) upon entering the decimal value, the value "3." will cast to integer value `3`, thus removing the decimal and preventing the user from entering their desired value.

In other words:

```js
console.log( Number( '3.' ) );
// => 3
```

Pull request description:
Fixes #61: Allow users to enter float in number field.
This patch allows users to enter a float in a `NumberField`.

r=? @magopian /cc @aduth

Patch:
diff --git a/src/utils.js b/src/utils.js
index 498cfbeaa..320b94674 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -76,6 +76,11 @@ export function getDefaultFormState(schema) {
 }
 
 export function asNumber(value) {
+  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.
+    return value;
+  }
   const n = Number(value);
   const valid = typeof n === "number" && !Number.isNaN(n);
   return valid ? n : value;


Test patch:
diff --git a/test/index_test.js b/test/index_test.js
index 219eb73a6..9c6d68608 100644
--- a/test/index_test.js
+++ b/test/index_test.js
@@ -333,6 +333,18 @@ describe("Form", () => {
         expect(node.querySelector(".field input").getAttribute("value"))
           .eql("2");
       });
+
+      it("should not cast the input as a number if it ends with a dot", () => {
+        const {comp, node} = createComponent({schema: {
+          type: "number",
+        }});
+
+        Simulate.change(node.querySelector("input"), {
+          target: {value: "2."}
+        });
+
+        expect(comp.state.formData).eql("2.");
+      });
     });
 
     describe("SelectWidget", () => {
diff --git a/test/utils_test.js b/test/utils_test.js
index 827b0cf65..9b7852bd1 100644
--- a/test/utils_test.js
+++ b/test/utils_test.js
@@ -1,6 +1,6 @@
 import { expect } from "chai";
 
-import { getDefaultFormState, isMultiSelect } from "../src/utils";
+import { asNumber, getDefaultFormState, isMultiSelect } from "../src/utils";
 
 
 describe("utils", () => {
@@ -81,6 +81,20 @@ describe("utils", () => {
     });
   });
 
+  describe("asNumber()", () => {
+    it("should return a number out of a string representing a number", () => {
+      expect(asNumber("3")).eql(3);
+    });
+
+    it("should return a float out of a string representing a float", () => {
+      expect(asNumber("3.14")).eql(3.14);
+    });
+
+    it("should return the raw value if the input ends with a dot", () => {
+      expect(asNumber("3.")).eql("3.");
+    });
+  });
+
   describe("isMultiSelect()", () => {
     it("should be true if schema items enum is an array and uniqueItems is true", () => {
       let schema = {items: {enum: ["foo", "bar"]}, uniqueItems: true};