In Svelte, is there a way to undo invalid user input, without triggering a momentarily fake property change for state?
For example (try it online), when user types in 123a
in the input
box, I want to covert it to a number and assign it counter
.
For that, I have to introduce a temporary and redundant change to counter
(using Number.NaN
below). Otherwise, counter
won't change, and 123a
will remain inside the input
box, while I want to revert it back to 123
:
<script>
let count = 0;
const handleClick = () => count ;
const handleChange = async e => {
const userValue = e.target.value;
let newValue = userValue? parseInt(userValue): 0;
if (isNaN(newValue)) newValue = count;
count = Number.NaN;
await Promise.resolve();
count = newValue;
};
</script>
Count: <button on:click={handleClick}>{count}</button>
<br />
A: <input value={count} on:input={handleChange} />
<br />
Is there a better way of doing it? Essentially, I want trigger a manual re-render for a part of my Svetle component, without changing the state.
Of course, in the event handler I could undo the change just by modifying e.target.value
directly:
const handleChange = async e => {
const userValue = e.target.value;
let newValue = userValue? parseInt(userValue): 0;
if (isNaN(newValue)) newValue = count;
if (newValue == count)
e.target.value = count;
else
count = newValue;
};
But I wonder if there's a way to tell Svelte to re-render the whole <input>
?
To compare, here's how I could do it in React (try it online):
function App() {
let [count, setCount] = useState(0);
const handleClick = () => setCount((count) => count 1);
const handleChange = (e) => {
const userValue = e.target.value;
let newValue = userValue ? parseInt(userValue) : 0;
if (isNaN(newValue)) newValue = count;
setCount(newValue);
};
return (
<>
Count: <button onClick={handleClick}>{count}</button>
<br />
A: <input value={count} onInput={handleChange} />
<br />
</>
);
}
CodePudding user response:
You simply need to bind
count to the value of the input. REPL
<script>
let count = 0;
const handleClick = () => count ;
const handleChange = (e) => {
const userValue = e.target.value;
const newValue = userValue ? parseInt(userValue, 10) : 0;
count = isNaN(newValue) ? count : newValue;
};
</script>
Count: <button on:click={handleClick}>{count}</button>
<br />
A: <input bind:value={count} on:input={handleChange} />
<br />
Note: Remember to always pass a radix to parseInt()
, it does not default to 10.