Polaris-react: TextField will not render value prop if passed a number

Created on 27 Jan 2020  路  9Comments  路  Source: Shopify/polaris-react

Issue summary

<TextField/> will not render value when passed a number. This happens even if `type="number"'

Expected behavior

When a number is passed to the value prop <TextField/> should render the value

Actual behavior

No value is rendered

Steps to reproduce the problem

  1. Go to code sandbox
  2. Type in number or use buttons to increment

Reduced test case

https://codesandbox.io/s/shopify-polaris-textfield-number-issue-u7kve

Specifications

  • Are you using the React components? (Y/N): Y
  • Polaris version number: 4.11.0
  • Browser: Chrome: 79.0.3945.79
  • Device: Laptop
  • Operating System: Windows 10

Or run npx envinfo --system --binaries --browsers --npmPackages react,react-dom,@shopify/polaris to provide specifications on your environment including version numbers, browser, device, and operating system.

Paste the results here:

  System:
    OS: Windows 10 10.0.18362
    CPU: (8) x64 Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
    Memory: 2.21 GB / 15.86 GB
  Binaries:
    Node: 10.15.3 - C:\Program Files\nodejs\node.EXE
    npm: 6.10.2 - C:\Program Files\nodejs\npm.CMD
  Browsers:
    Edge: 44.18362.449.0
    Internet Explorer: 11.0.18362.1
  npmPackages:
    react: ^16.12.0 => 16.12.0
    react-dom: ^16.12.0 => 16.12.0

Most helpful comment

Maybe y'all should consider creating a new component called NumberField if your not willing to allow TextField to render a number anymore.

All 9 comments

馃憢 Thanks for opening your first issue. A contributor should give feedback soon. If you haven鈥檛 already, please check out the contributing guidelines.

Looks like this was intended behavior:
https://github.com/Shopify/polaris-react/pull/2598/files#diff-ce1bd24f5c7c2bd4b9fb5d55a5aa97aeR186-R189

Same issue after updating from 4.10.2 to 4.11.0.
All the "input-type: number" textfields have stopped working at all.
TextFields just fail displaying any variables from redux store for me.

Found solution:
I have number variables in my redux store.
Before I were passing numbers directly to the textfield, and then parsing a string coming from textfield back to the number to store and work with it properly.
Now I pass my number variables to the textfield after parsing them to the string:
value={String( this.props.boosterTable.currentItem.dismissTime )}
Everything else is the same.
Just parse your number to the string before passing it to the TextField "value" prop.

Just parse your number to the string before passing it to the TextField "value" prop.

Yes my solution for every number input now is

const [myValue setMyValue] = useState(3)

const handleChange = useCallback((val) => setMyValue(Number(val)), [setMyValue])

<TextField value={myValue.toString()} onChange={handleChange}/>

Not ideal but some values I want stored as numbers

Heya @pklitscher,

As you've already found out TextField only supports passing a string into its value, per its type, and the solution is to call toString() on what you pass in.

It's typing has been this way for a long time and any usage of you passing a number into there that worked before v4.11.0 was due to accident rather than design.

This is because the value you get back from an onChange event on an <input> field is always a string and it would be confusing to start off with a state that is of type number, and then when an onChange event is triggered you store the value of the event target in that state, and thus change the type.

Consider the following code:

export function Playground() {
  // value starts off as a number
  const [value, setValue] = React.useState(3);

  const changeV = React.useCallback((event) => {
    console.log(typeof event.target.value, event.target.value);
    setValue(event.target.value);
  }, []);

  return (
    <input value={value} onChange={changeV} type="number" />;
  );
}

Here we have an initial state that is a number (3) and we pass that through to the input value. However say you type into the input field, adding a 4. The onChange event fires and the value of event.target.value is '34' - a string not a number. This would then get persisted into your state and now your state is a string ('34'). Note that having type=number has no effect on the value of the event target - it is always a string.

TextField seeks to avoid this potential for unexpected behaviour by ensuring that the value you pass in - and the value you get back from its onChange handler - is always a string.

Maybe y'all should consider creating a new component called NumberField if your not willing to allow TextField to render a number anymore.

NumberField

import React from "react";
import { TextFieldProps, TextField } from "@shopify/polaris";

const isNumber = (val: any) => !Number.isNaN(val);
interface INumberFieldProps
  extends Omit<TextFieldProps, "type" | "value" | "onChange"> {
  onChange(value: number, id: string): void;
  value?: number;
}
export default function NumberField(props: INumberFieldProps) {
  const { onChange, value, ...restProps } = props;
  const valueAsString = isNumber(value) ? value!.toString() : "";

  return (
    <TextField
      {...restProps}
      type="number"
      value={valueAsString}
      onChange={(val, id) => {
        const parsedVal = val ? parseInt(val) : null;

        const isNumber = !!(parsedVal && !Number.isNaN(parsedVal));

        isNumber && onChange(parsedVal as number, id);
      }}
    />
  );
}

Yup confirming the same issue using v4.16.1

Was this page helpful?
0 / 5 - 0 ratings

Related issues

alex-page picture alex-page  路  3Comments

janklimo picture janklimo  路  3Comments

shahab65 picture shahab65  路  3Comments

andrewpye picture andrewpye  路  3Comments

andrewpye picture andrewpye  路  3Comments