Answer the question
In order to leave comments, you need to log in
How to change the type and value at the right moment?
good evening.
need help with input component.
what is at the moment
1) there is an input. By default, the type prop is set to number. in the onchange, the value is run through a regular expression that cuts off signs, and nothing is entered at the output except integers.
2) props with the maximum allowed number.
3) there are pseudo buttons + - that add\reduce value by some n-number.
4) if the number is large, like 1000000, then onBlur the value is converted to a string, commas are substituted and the value becomes 1,000,000. on OnFocus, respectively, it is again a number, and the commas disappear.
actually the task is - when clicking on + - I get into onblur and I can't decrement\increment because it's a string at that moment.
The only thing I thought of was switching to focus and zero timeout on blur, but it didn't work.
const Input = ({
onChange,
disabled,
numStep = 1,
min = 0,
max,
value,
placeholder,
className,
type = 'number',
onBlur,
onFocus,
isPriceInput
}) => {
// STATES
const [isFocused, setIsFocused] = useState(false);
const [isEditing, setEditing] = useState(false);
// HANDLES
const handle = {
change: (e) => {
let inputValue = e.target ? onlyNumbers(e.target.value) : e;
if (inputValue !== '') {
// inputValue = inputValue.toString().replace(/\D/g, '');
inputValue = parseFloat(inputValue) || '';
if (min && +min > +inputValue) {
inputValue = +min;
} else if (max && +max < +inputValue) inputValue = +max;
}
onChange(inputValue.toString());
},
toggleEdit: () => {
setEditing(!isEditing);
onChange('');
},
focus: (e) => {
setIsFocused(true);
if (isPriceInput) onChange(removeComma(value));
if (onFocus) onFocus(e);
},
blur: (e) => {
setIsFocused(false);
setEditing(false);
if (isPriceInput) onChange(addCommas(value));
if (onBlur) onBlur(e);
},
decrement: () => {
handle.change(+value - +numStep);
},
increment: () => {
handle.change(+value + +numStep);
}
};
useEffect(() => {
if (isEditing || isFocused) inputRef.current.focus();
}, [isEditing, isFocused]);
const uniProps = {
className: `input ${className}`,
placeholder,
value: value || '',
disabled,
onChange: handle.change,
onFocus: handle.focus,
onBlur: handle.blur,
onKeyUp: handle.keyUp,
min,
max,
...(maskChar ? { maskChar } : {}),
...(formatChars ? { formatChars } : {})
};
return (
<div className='input__wrap'>
<input {...uniProps} ref={inputRef} type={type} />
<div className='input__nums'>
<button
onClick={() => handle.decrement()}
className={cn(`input__num-btn`, { disabled: value <= min })}
>
<Minus />
</button>
<button
onClick={() => handle.increment()}
className={cn(`input__num-btn`, { disabled: value >= max })}
>
<Plus />
</button>
</div>
</div>
);
export default Input;
addCommas: (value) => {
value = value.toString();
const isFraction = value.includes('.');
const valueBeforeDot = isFraction
? value.slice(0, value.indexOf('.'))
: value;
const intPart = valueBeforeDot
.split('')
.reverse()
.reduce(
(acc, item, idx) =>
idx % 3 === 0 && idx !== 0 ? [...acc, ',', item] : [...acc, item],
[]
)
.reverse()
.join('');
return isFraction ? intPart + value.slice(value.indexOf('.')) : intPart;
},
removeComma: (value) => {
return parseFloat(value.replace(/\,/g, ''));
}
},
onlyNumbers: (value, isDot = false) => {
const val =
value.slice(0, 1) !== '0' && value.slice(0, 1) !== '.'
? value
: value.slice(1);
if (isDot) return twoDigitAfterDot(val.replace(/[^0-9.]/g, ''));
else return +val.toString().replace(/\D/g, '');
},
Answer the question
In order to leave comments, you need to log in
Inside increment and decrement use removeComma if there is a string.
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question