Initializing React number input control with blank value? - javascript

I'd like my controlled input to initialize with no value in the box.
The input is a number, so I don't pass in an empty ''.
Using defaultProps, I initialize the input with a null.
When typing into the input the console reports this message:
<MyInput> is changing an uncontrolled input of type number to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa).
To prevent this normally I initialize with an empty string to prevent this "switching" from happening. But with a number (I don't want to show a 0, I want nothing to show) I am not sure how to do it.
static defaultProps = {
estimatedHours: null,
estimatedMinutes: null,
}
defalut values ^^
<input
type="number"
onChange={(e) => this.handleChange('Hours', e.target.value)}
onKeyDown={this.handleKeyDown}
onPaste={this.handlePaste}
value={estimatedHours}
placeholder={hoursText}
className="slds-input th-trailmix-textbox th-time-component__input"
/>

Simpler approach is to have a fallback value be an empty string.
Works for type=number as well.
<input type="number" value={estimatedHours || ''} />

You can set value Undefined,
Also add a check for input type if required
class Input extends React.Component {
constructor(props) {
super(props);
this.state = {value: undefined};
this.handleChange = this.handleChange.bind(this);
}
handleChange = (event) => {
const isnum = /^\d+$/.test(event.target.value);
if (isnum) {
return this.setState({
value: Number(event.target.value),
});
}
};
render() {
return (
<input
type="number"
onChange={this.handleChange}
value={String(this.state.value)}
placeholder={"Please enter number"}
/>
);
}
}
and convert String to Number and vice versa
This won't throw you an error for uncontrolled input

I'd like my controlled input to initialize with no value in the box.
my problem is that I want a controlled number input with a null /
undefined initial value.
I suggest defaulting the value props in the input element with an empty string like the following:
<input
type="number"
// ...
value={estimatedHours === undefined ? '' : estimatedHours}
/>
This will make the input empty and prevent the warning from React. It'll also conveniently work well with the required prop too so the user must enter an input.
In TypeScript 3.7+, it can be shorted to the following using the nullish coalescing operator:
<input
type="number"
// ...
value={estimatedHours ?? ''}
/>

Uncontrolled inputs are simply inputs where you aren't tying value to JavaScript. So if you are rendering:
<input value={any} />
That is a controlled input.
If you want to render an uncontrolled input with an empty value you could simply write
<input type="number" /> or <input type="number" placeholder="" />
or <input type="number" placeholder="please enter a number..." />
Next, if you want to pull the value use a ref.
state = {
query: ''
}
handleSubmit = (e) => {
e.preventDefault()
this.setState({ query: this.search.value })
}
render() {
return (
<form>
<input
type="number"
ref={input => this.search = input}
placeholder=""
/>
<button type="submit" onClick={this.handleSubmit}>Submit</button>
</form>
)
}
Additionally, you can still perform logic on the return value if you need to. ie:
handleSubmit = (e) => {
e.preventDefault()
this.setState({ query: this.search.value.toExponential(2) })
// square whatever the user inputs and store in this.state.query
}

The easiest way to get the behaviour you are looking for is to define the prop type for this field to a string. This will allow '' to be used as a default prop. On form submission, you will need to make sure that the value of this field is parsed to a number.
type FormProps = {
estimatedHours: string;
estimatedMinutes: string;
}
FormProps.defaultProps = {
estimatedHours: '',
estimatedMinutes: '',
}

Related

React hook form only allow numbers greater than 0

I'm using React Hook Form to make an input for height, weight and length. The value cannot be 0 - it has to be at least 1 or more. I tried different ways such as: pattern with regex, validate and more. But I am unable to figure out how to prevent the input field from letting the user type in '0' ( only as the first character ). I also tried type="number" and min="1" however it's not changing anything. Any ideas would be greatly appreciated.
<Input
{...form.register(`pallets.${index}.weight`, {
required: t('errors.emptyInput'),
pattern: {
value: /^[^1-9]/,
message: 'hello',
},
validate: (value) => {
return [/^[^1-9]/].every((pattern) => pattern.test(value))
},
})}
type='number'
/>
It appears to me that pattern does not change anything. Only type= 'number' actually affects the way the input field works.
<input
type="number"
{...register("test", {
min: 1
})}
/>
You can check the detailed usage from the documentation.
You can take advantage of react useState hook to implement this functionality.
export default function App() {
const [x, setX] = useState(null);
const handleChange = e => {
const value = e.target.value;
if (!value || /^[1-9]\d*/.test(value))
setX(e.target.value)
}
return (
<div className="App">
<input type="number" value={x} onChange={handleChange} />
</div>
);
}

Input in javascript from user handling

I am trying to type and save data from a input field in a Modal. For some reason I cant type inside the field once I render the modal.
This is my code:
constructor(props){
super(props);
this.state = {
showHide : false,
email: ' '
}
}
handleChange = (e) => {
this.setState({
[e.target.email]: e.target.value
})
}
This is where I attempted to have the user input.
<FormGroup>
<label for="message-text" class="col-form-label">Email Adress:</label>
<input type="text" class="form-control" name='email' placeholder="Email"
value={this.state.email} onChange={e => this.handleChange(e)} >
</input>
</FormGroup>
Any ideas on why I cant type inside the the field? Please and thank you.
So the mistake is within your setState, you have to use e.target.name. This name property will provide a string value 'email' as set in input.
Description:
Name is an HTML attribute that is accessible from Event object being passed into the function, this name is set as 'email' in your input as you can see. And since you are not updating the state correctly, that input which is right now a controlled component (value bound to state) isn't being updated.
For more details look into ES6 computed names properties.
this.setState({
[e.target.name]: e.target.value
})

React Js Data Handling

how are you? I come here to ask for your help. I'm with React JS, I have these states that are requested to send them by post to generate a user.-
class NuevoUsuario extends Component{
constructor(props){
super(props)
this.state = {
usuario: '',
password: '',
persona: {
apellido:'',
apellidoCasada:'',
nombre:'',
dni:'',
telefono:'',
celular:'',
email:'',
ubicacion: {
direccion:'',
ciudad:'',
provincia:'',
codigoPostal:'',
paisId: 0,
}
}
}
this.handleInput = this.handleInput.bind(this);
}
handleInput(e){
this.setState({[e.target.name]: e.target.value })
console.log(this.state);
}
Now what I want is that from
<div className="form-group">
<label htmlFor="exampleInput">Apellido</label>
<input
className="form-control input-lg"
type="text"
name="apellido"
onChange={this.handleInput}
/>
</div>
when doing that, the username and password are assigned, but the last name and all the others are not assigned to person.lastname or person.name, a new state is added as well, and those of person are empty {}
What I want is to be kept in person.surname. If you can help me I will be very grateful
Your input tag has attribute name that you use to select which property in state to update
<input
className="form-control input-lg"
type="text"
name="apellido"
onChange={this.handleInput}
/>
And handleInput use e.target.name to specify which property to update
handleInput(e){
this.setState({[e.target.name]: e.target.value })
console.log(this.state);
}
e.target.name will be equal to apellido, so this.state.apellido will be equal to input value.
Setting name=persona.apellido will not solve you task. You'll not be able to access this.state.persona.apellido.
The easiest solutuion I see is to make state one plane object without nested obects. Like so
this.state = {
usuario: '',
password: '',
apellido:'',
apellidoCasada:'',
nombre:'',
dni:'',
// And so on
}
Another solution is to parse this.target.name in handleInput like so (not tested!)
handleInput(e){
let name = e.target.name.split('.');
switch (name.length)
case 1:
this.setState({[e.target.name]: e.target.value });
break;
case 2:
this.setState({[name[0]]: {...this.state[name[0]], [name[1]]: e.target.value }});
break;
case 3:
this.setState({[name[0]]: {...this.state[name[0]], [name[1]]: { ...this.state[name[0]][name[1]], [name[2]]: e.target.value }}});
break;
default:;
}
console.log(this.state);
}
But I not reccomend second solution as it overcomplicated and harder to maintain in future.
First of all, in React, you need a 2-way binding between your state and input fields. You do that by adding a value prop to your input like below:
<input
className="form-control input-lg"
type="text"
name="apellido"
value={ this.state.persona.apellido } <----- Two Way
onChange={this.handlePersonaInput} <----- Binding
/>
Second, your username and password fields work because your handleInput method can only find their values in the state's first level of depth. Your Persona variables are in the second level of the state depth, and your address info is in the third level of depth. In order to reach Persona values, you need to setup a second input handler:
handlePersonaInput(e){
this.setState({persona[e.target.name]: e.target.value })
}
and your persona address fields will have third input handler:
handleAddressInput(e){
this.setState({persona.ubicacion[e.target.name]: e.target.value })
}
If you're not satisfied with 3 input handlers in your component, you can merge them into one like below:
handleInput(e){
const { name, value } = e.target;
if (name === 'usuario' || name === 'password')
this.setState({[name]: value });
else if (name === 'apellido' || name === 'apellidoCasada' || etc..)
this.setState({persona[name]: value });
else if (name === 'direccion' || etc..)
this.setState({persona.ubicacion[name]: value });
}
Just remember to think about your state structure when you want to modify one of its variables.

ReactJS OnKeyUp event not getting value on controlled input

I'm building a ReactJS search component for data filtering through search.
The idea is that the user types a word, letter after letter, and the system will filter all registers containing that word. The basic component is detailed below:
class SearchInput extends Component {
static propTypes = {
onKeyUp: PropTypes.func,
placeHolder: PropTypes.string,
value: PropTypes.string
};
state = {
searchText: ""
};
handleKeyUp = event => {
console.log(event.target.value) // <== No result. Always empty
let newSearchText = event.target.value;
this.setState({ searchText: newSearchText });
if (this.props.onKeyUp) this.props.onKeyUp(newSearchText);
};
render() {
console.log(this.state.searchText) // <== Always empty
return (
<div className="search-input">
<div className="search-input-icon">
<Icon name="faSearch" />
</div>
<input
autoFocus="true"
type="text"
onKeyUp={this.handleKeyUp}
placeholder={this.props.placeHolder}
value={this.state.searchText}
/>
</div>
);
}
I'm not getting the key pressed value on the handleKeyUp event handler.
It works if I ommit the value={this.state.searchText} (uncontrolled) from the code, but I need a way to set the searchText from outside the component (initialization, other component selection, etc.).
Why am I not getting the event.target.value data on my handler? How to fix it?
I'm pretty sure you have to listen to the onChange event on an input field to get the updated target value. simply change
<input onKeyUp={this.handleKeyUp} />
to
<input onChange={this.handleKeyUp} />
Try to use event.key instead.
The event.target.value just points to your this.state.searchText which hasn't been set yet.
seems you forgot to bind the function on the constructor:
class SearchInput extends Component {
constructor(props) {
super(props);
this.handleKeyUp = this.handleKeyUp.bind(this);
}
//... any code here
handleKeyUp = event => {
console.log(event.target.value);
}
render() {
//... any code here
<input
autoFocus="true"
type="text"
onKeyUp={this.handleKeyUp}
placeholder={this.props.placeHolder}
value={this.state.searchText}
/>
}
}
Use this:
let newSearchText = event.target.getAttribute('value')

React - changing an uncontrolled input

I have a simple react component with the form which I believe to have one controlled input:
import React from 'react';
export default class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
return (
<form className="add-support-staff-form">
<input name="name" type="text" value={this.state.name} onChange={this.onFieldChange('name').bind(this)}/>
</form>
)
}
onFieldChange(fieldName) {
return function (event) {
this.setState({[fieldName]: event.target.value});
}
}
}
export default MyForm;
When I run my application I get the following warning:
Warning: MyForm is changing an uncontrolled input of type text to be
controlled. Input elements should not switch from uncontrolled to
controlled (or vice versa). Decide between using a controlled or
uncontrolled input element for the lifetime of the component
I believe my input is controlled since it has a value. I am wondering what am I doing wrong?
I am using React 15.1.0
I believe my input is controlled since it has a value.
For an input to be controlled, its value must correspond to that of a state variable.
That condition is not initially met in your example because this.state.name is not initially set. Therefore, the input is initially uncontrolled. Once the onChange handler is triggered for the first time, this.state.name gets set. At that point, the above condition is satisfied and the input is considered to be controlled. This transition from uncontrolled to controlled produces the error seen above.
By initializing this.state.name in the constructor:
e.g.
this.state = { name: '' };
the input will be controlled from the start, fixing the issue. See React Controlled Components for more examples.
Unrelated to this error, you should only have one default export. Your code above has two.
When you first render your component, this.state.name isn't set, so it evaluates to undefined or null, and you end up passing value={undefined} or value={null}to your input.
When ReactDOM checks to see if a field is controlled, it checks to see if value != null (note that it's !=, not !==), and since undefined == null in JavaScript, it decides that it's uncontrolled.
So, when onFieldChange() is called, this.state.name is set to a string value, your input goes from being uncontrolled to being controlled.
If you do this.state = {name: ''} in your constructor, because '' != null, your input will have a value the whole time, and that message will go away.
Another approach it could be setting the default value inside your input, like this:
<input name="name" type="text" value={this.state.name || ''} onChange={this.onFieldChange('name').bind(this)}/>
I know others have answered this already. But a very important factor here that may help other people experiencing similar issue:
You must have an onChange handler added in your input field (e.g. textField, checkbox, radio, etc). Always handle activity through the onChange handler.
Example:
<input ... onChange={ this.myChangeHandler} ... />
When you are working with checkbox you may need to handle its checked state with !!.
Example:
<input type="checkbox" checked={!!this.state.someValue} onChange={.....} >
Reference: https://github.com/facebook/react/issues/6779#issuecomment-326314716
Simple solution to resolve this problem is to set an empty value by default :
<input name='myInput' value={this.state.myInput || ''} onChange={this.handleChange} />
One potential downside with setting the field value to "" (empty string) in the constructor is if the field is an optional field and is left unedited. Unless you do some massaging before posting your form, the field will be persisted to your data storage as an empty string instead of NULL.
This alternative will avoid empty strings:
constructor(props) {
super(props);
this.state = {
name: null
}
}
...
<input name="name" type="text" value={this.state.name || ''}/>
I had the same problem.
the problem was when i kept the state info blank
const [name, setName] = useState()
I fixed it by adding empty string like this
const [name, setName] = useState('')
In my case, I was missing something really trivial.
<input value={state.myObject.inputValue} />
My state was the following when I was getting the warning:
state = {
myObject: undefined
}
By alternating my state to reference the input of my value, my issue was solved:
state = {
myObject: {
inputValue: ''
}
}
When you use onChange={this.onFieldChange('name').bind(this)} in your input you must declare your state empty string as a value of property field.
incorrect way:
this.state ={
fields: {},
errors: {},
disabled : false
}
correct way:
this.state ={
fields: {
name:'',
email: '',
message: ''
},
errors: {},
disabled : false
}
If the props on your component was passed as a state, put a default value for your input tags
<input type="text" placeholder={object.property} value={object.property ? object.property : ""}>
Set a value to 'name' property in initial state.
this.state={ name:''};
An update for this. For React Hooks use const [name, setName] = useState(" ")
Simply create a fallback to '' if the this.state.name is null.
<input name="name" type="text" value={this.state.name || ''} onChange={this.onFieldChange('name').bind(this)}/>
This also works with the useState variables.
I believe my input is controlled since it has a value.
Now you can do this two ways the best way is to have a state key to each input with 1 onChange handler. If you have checkboxes you will need to write a separate onChange handler.
With a Class component you would want to write it like this πŸ‘‡
import React from 'react';
export default class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = {
myFormFields: {
name: '',
dob: '',
phone: ''
}
}
this.onFormFieldChange = this.onFormFieldChange.bind(this)
}
// Always have your functions before your render to keep state batches in sync.
onFormFieldChange(e) {
// No need to return this function can be void
this.setState({
myFormFields: {
...this.state.myFormFields,
[e.target.name]: e.target.value
}
})
}
render() {
// Beauty of classes we can destruct our state making it easier to place
const { myFormFields } = this.state
return (
<form className="add-support-staff-form">
<input name="name" type="text" value={myFormFields.name} onChange={this.onFormFieldChange}/>
<input name="dob" type="date" value={myFormFields.dob} onChange={this.onFormFieldChange}/>
<input name="phone" type="number" value={myFormFields.phone} onChange={this.onFormFieldChange}/>
</form>
)
}
}
export default MyForm;
Hope that helps for a class but the most performative and what the newest thing the devs are pushing everyone to use is Functional Components. This is what you would want to steer to as class components don't intertwine well with the latest libraries as they all use custom hooks now.
To write as a Functional Component
import React, { useState } from 'react';
const MyForm = (props) => {
// Create form initial state
const [myFormFields, setFormFields] = useState({
name: '',
dob: '',
phone: ''
})
// Always have your functions before your return to keep state batches in sync.
const onFormFieldChange = (e) => {
// No need to return this function can be void
setFormFields({
...myFormFields,
[e.target.name]: e.target.value
})
}
return (
<form className="add-support-staff-form">
<input name="name" type="text" value={myFormFields.name} onChange={onFormFieldChange}/>
<input name="dob" type="date" value={myFormFields.dob} onChange={onFormFieldChange}/>
<input name="phone" type="number" value={myFormFields.phone} onChange={onFormFieldChange}/>
</form>
)
}
export default MyForm;
Hope this helps! 😎
In short, if you are using class component you have to initialize the input using state, like this:
this.state = { the_name_attribute_of_the_input: "initial_value_or_empty_value" };
and you have to do this for all of your inputs you'd like to change their values in code.
In the case of using functional components, you will be using hooks to manage the input value, and you have to put initial value for each input you'd like to manipulate later like this:
const [name, setName] = React.useState({name: 'initialValue'});
If you'd like to have no initial value, you can put an empty string.
In my case component was rerendering and throwing A component is changing an uncontrolled input of type checkbox to be controlled error. It turned out that this behaviour was a result of not keeping true or false for checkbox checked state (sometimes I got undefined). Here what my faulty component looked like:
import * as React from 'react';
import { WrappedFieldProps } from 'redux-form/lib/Field';
type Option = {
value: string;
label: string;
};
type CheckboxGroupProps = {
name: string;
options: Option[];
} & WrappedFieldProps;
const CheckboxGroup: React.FC<CheckboxGroupProps> = (props) => {
const {
name,
input,
options,
} = props;
const [value, setValue] = React.useState<string>();
const [checked, setChecked] = React.useState<{ [name: string]: boolean }>(
() => options.reduce((accu, option) => {
accu[option.value] = false;
return accu;
}, {}),
);
React.useEffect(() => {
input.onChange(value);
if (value) {
setChecked({
[value]: true, // that setChecked argument is wrong, causes error
});
} else {
setChecked(() => options.reduce((accu, option) => {
accu[option.value] = false;
return accu;
}, {}));
}
}, [value]);
return (
<>
{options.map(({ value, label }, index) => {
return (
<LabeledContainer
key={`${value}${index}`}
>
<Checkbox
name={`${name}[${index}]`}
checked={checked[value]}
value={value}
onChange={(event) => {
if (event.target.checked) {
setValue(value);
} else {
setValue(undefined);
}
return true;
}}
/>
{label}
</LabeledContainer>
);
})}
</>
);
};
To fix that problem I changed useEffect to this
React.useEffect(() => {
input.onChange(value);
setChecked(() => options.reduce((accu, option) => {
accu[option.value] = option.value === value;
return accu;
}, {}));
}, [value]);
That made all checkboxes keep their state as true or false without falling into undefined which switches control from React to developer and vice versa.
For people using Formik, you need to add a default value for the specific field name to the form's initialValues.
This generally happens only when you are not controlling the value of the filed when the application started and after some event or some function fired or the state changed, you are now trying to control the value in input field.
This transition of not having control over the input and then having control over it is what causes the issue to happen in the first place.
The best way to avoid this is by declaring some value for the input in the constructor of the component.
So that the input element has value from the start of the application.
Please try this code
import React from "react";
class MyForm extends React.Component {
constructor(props) {
super(props);
this.state = { name: "" };
this.onFieldChange = this.onFieldChange.bind(this);
}
onFieldChange(e) {
this.setState({[e.target.name]: e.target.value});
}
render() {
return (
<form className="add-support-staff-form">
<input name="name" type="text" value={this.state.name} onChange={this.onFieldChange} />
</form>
);
}
}
export default MyForm;
In my case there was spell mistake while setting the state which was causing defined value to be undefined.
This is my default state with value
const [email, setEmail] = useState(true);
my mistake was-
setEmail(res?.data?.notificationSetting.is_email_notificatio);
and the solution is -
setEmail(res?.data?.notificationSetting.is_email_notification);
last char was missing
I had the same issue with type='radio'
<input type='radio' checked={item.radio} ... />
the reason was that item.radio is not always true or false, but rather true or undefined, for example. Make sure it’s always boolean, and the problem will go away.
<input type='radio' checked={!!item.radio} ... />
source
For dynamically setting state properties for form inputs and keeping them controlled you could do something like this:
const inputs = [
{ name: 'email', type: 'email', placeholder: "Enter your email"},
{ name: 'password', type: 'password', placeholder: "Enter your password"},
{ name: 'passwordConfirm', type: 'password', placeholder: "Confirm your password"},
]
class Form extends Component {
constructor(props){
super(props)
this.state = {} // Notice no explicit state is set in the constructor
}
handleChange = (e) => {
const { name, value } = e.target;
this.setState({
[name]: value
}
}
handleSubmit = (e) => {
// do something
}
render() {
<form onSubmit={(e) => handleSubmit(e)}>
{ inputs.length ?
inputs.map(input => {
const { name, placeholder, type } = input;
const value = this.state[name] || ''; // Does it exist? If so use it, if not use an empty string
return <input key={name} type={type} name={name} placeholder={placeholder} value={value} onChange={this.handleChange}/>
}) :
null
}
<button type="submit" onClick={(e) => e.preventDefault }>Submit</button>
</form>
}
}

Categories