React: Bind number input to state (handle intermediate values) - javascript

I have a number stored in my React state, and I want to edit it using an <input type="number" />. Here's my attempt:
function MyNumberInput() {
const [number, setNumber] = useState(42);
return (
<input
type="number"
value={number}
onChange={event => {
setNumber(parseFloat(event.target.value)); // Convert string value to a number!
}}
/>
);
}
Try it on JSFiddle.
The problem is that this code fails during intermediate, non-number states. If I want to enter -12, I begin by typing the negative sign. When I do, the onChange handler fires, parseFloat("-") returns NaN, and the input remains empty. As a user, it feels like my input was completely ignored.

just use unary plus operator to convert a string into a number like this:
function MyNumberInput() {
const [number, setNumber] = useState(42);
return (
<input
type="number"
value={number}
onChange={event => {
setNumber(+(event.target.value)); // Convert string value to a number!
}}
/>
);
}

Use RegEx
The problem is the input get NaN is because the input type="number" and - or . is not a number.
I suggest to use RegEx:
function MyNumberInput() {
const [number, setNumber] = useState(42);
const updateNumber = ({ target }) => {
const reg = new RegExp('^[0-9+-/]+$|^$');
if (reg.test(target.value)) setNumber(target.value);
};
return (
<input type="text" value={number} onChange={updateNumber} />
);
}

You may want to remove the below props to enable non-number content input.
type="number"
And remove the parseFloat to store the string like - or .0
import React, { useState } from "react";
import "./styles.css";
export default function App() {
const [number, setNumber] = useState('');
return (
<div className="App">
<input
value={number}
onChange={event => {
// console.log(event.currentTarget.value);
setNumber(event.target.value);
}}
/>
</div>
);
}
Try it online:

Related

how to add thousand separator for number input fields in react?

I want to add thousand separators to an number input however I don't want to change the value. I add the separators but the value will become string.
import "./styles.css";
import { useState } from "react";
export default function App() {
const [value, setValue] = useState(0);
const addCommas = (num) =>
num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
const removeNonNumeric = (num) => num.toString().replace(/[^0-9]/g, "");
const handleChange = (event) =>
setValue(addCommas(removeNonNumeric(event.target.value)));
console.log(typeof value)
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<input type="text" value={value} onChange={handleChange} />
</div>
);
}
In this code as soon as user enters a number, the typeof value will become string since we are using toString method.
I was wondering if there is a way to implement an input and only modify its view not its value.
using this code solve this problem the code is below and another little thing i can say may be none numaric string are not able to convert to number and the thing is that a comma as like none numaric string that's why you got NaN see the code solution:
import "./styles.css";
import { useState } from "react";
export default function App() {
const [value, setValue] = useState({
displayValue: 0,
actualNumberValue: 0
});
const handleChange = (event) => {
const strNumber = event.target.value.replace(/[^0-9]/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, ",");
setValue({
displayValue: strNumber,
actualNumberValue: Number(strNumber.replace(/,/g, ""))
});
};
console.log(typeof value.actualNumberValue);
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<input type="text" value={value.displayValue} onChange={handleChange} />
</div>
);
}

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>
);
}

two way binding string separated by commas

This is my object:
const [opportunity, setOpportunity] = useState({
name: '',
description: '',
experience: '',
});
I want to store it in the opportunity experience property like a string separated by commas. Like this for example: 'experience_1,experience_2,experience_3'.
But when i type in the input field i want to be able to have space between the words. Like this for example: experience_1 experience_2 experience_3
this is my code for the input field:
<InputField
type='text'
value={opportunity.experience.split(',').join(' ')} // i think i need changes here
onChange={(e) => setOpportunity({ ...opportunity, experience: e.currentTarget.value.split(" ").filter(x => x !== '').toString() })} // i think this works
label={"Experiences"}
/>
Any Help Guys?
Replace .filter(x => x !== '') with .replace(/\s+/g, " ") and place it before you call the .split() method. This will replace multiple spaces with a single space, and prevent the user from entering in more than one space at a time, while letting them change the contents of your InputField component. Remember, .filter() works on a cloned copy of the string while .replace() works on the string itself, which in this case is the event current target value.
Now it should work as intended.
Like so:
<InputField
type="text"
value={opportunity.experience
.split(",")
.map((x) => x.trim()) // Added .trim() to keep consistent spacing...
.join(" ")} // ...before joining
onChange={(e) => {
setOpportunity({
...opportunity,
experience: e.currentTarget.value
.replace(/\s+/g, " ") // If you try to use .filter() here, it won't work
.split(" ")
.toString(),
});
}}
label={"Experiences"}
/>
I've also chained a trim operation on each value from the state property with .map() to keep the spacing consistent during presentation, in the event that the state property was initialized with lots of spaces in between each experience value.
Here's an updated example of my previous answer using useEffect to update the state based on the input value. This keeps the input value and the state value separate.
working code sandbox
import React from "react";
export default function App() {
return (
<div className="App">
<MyComponent />
</div>
);
}
const MyComponent = () => {
const [opportunity, setOpportunity] = React.useState({
name: "",
description: "",
experience: []
});
const [experienceValue, setExperienceValue] = React.useState("");
React.useEffect(() => {
const experience = experienceValue.split(" ").filter((x) => x !== "");
setOpportunity({ ...opportunity, experience });
}, [experienceValue, opportunity]);
const handleInput = (e) => {
setExperienceValue(e.currentTarget.value);
};
return (
<>
<input type="text" value={experienceValue} onChange={handleInput} />
<br />
{JSON.stringify(opportunity.experience)}
</>
);
};

Not able to remove first 3 digit of phone number in react

In the phone number Text-field if you type any number like 919002007805 in the console its print normally but if you want to remove number one by one then up to 9 digits its working fine(919*********) then if you want to remove first 3 digits from input(919) you observe in console its not reflecting ,but in Input its removed ,so when I want to update the phone number the flag give some unwanted symbol. so how to resolved that one so that in console its working fine at the time of inserting as well deleting time.
import React from "react";
import PhoneInput from "react-phone-number-input";
export default function App() {
const [fields, setFields] = React.useState([{ value: null }]);
function handleChange(i, event) {
if (event) {
let values = [...fields];
values[i].value = event;
setFields((v) => values);
console.log(`values`, values[0]);
}
}
return (
<div className="App">
{fields.map((field, idx) => (
<PhoneInput
key={idx}
id="phoneNumbers1"
type="text"
placeholder="Enter phone number "
value={field.value || ""}
defaultCountry="IN"
international
name="phoneNumbers"
autoComplete="off"
onChange={(e) => handleChange(idx, e)}
/>
))}
</div>
);
}

input initial Value react js

I have questionand I hope you can help me to find right answer.
I have the following code.
import Slider from '#material-ui/core/Slider';
export default function RangeSlider({setValue1}) {
const location = useLocation();
const classes = useStyles();
const [value, setValue] = useState(['', 150000]);
const handleChange = (event, newValue) => {
setValue(newValue);
setValue1(value);
};
useEffect(() => {
setValue(['', 150000]);
setValue1(value);
}, [location.search]);
return (
<div className={`filter-slider-wrapper ${classes.root} `}>
<p>
<input
type="number"
className="slider-input"
onChange={({target}) => {
if (target.value.length > 7) {
return false;
}
setValue([+target.value, value[1]]);
setValue1(value);
}}
value={value[0]}
/>
</p>
<Slider value={value} onChange={handleChange} min={1} max={150000} />
<p>
<input
type="number"
className="slider-input"
onChange={({target}) => {
if (target.value.length > 7) {
return false;
}
setValue([value[0], +target.value]);
setValue1(value);
}}
value={value[1]}
/>
</p>
</div>
);
}
When I typeing something in input and after that I delleting form input everything was deleted, but after that "0" number was appeared and it was not deleteable, how can I avoid that case?
Thank you everybody.
I alredy resolved this problem.
I just deleted "+" symbol in setValue([+target.value, value[1]]);
Now the correct way to avoid "0" number to write without "+" symbol
Right way is: setValue([target.value, value[1]]);

Categories