In the following component (range.svelte) why do I have to do inputElement.value = valueToSet; at line 24 when the input element value is bound to value (<input value={value}...)? Why isn’t the assignment to value just before at line 27 sufficient?
Some more context: the idea is for the user not to be able to enter a number outside of the range in the "number" type input.
<script lang="ts">
import { RangeSlider } from '@skeletonlabs/skeleton';
export let value: number;
export let suffix: string;
export let min: number;
export let max: number;
export let name: string;
export let step: number = 1;
let clazz: string = ""
export {clazz as class};
function onInputChanged(event: Event): void {
const inputElement = event.target;
const newValue = inputElement.value;
const valueToSet = computeValueToSet(newValue);
value = valueToSet
inputElement.value = valueToSet;
}
function computeValueToSet(newValue: string): number {
if (newValue === "") {
return value;
}
const newInt = parseInt(newValue, 10);
const isInRange = min <= newInt && newInt <= max;
if (!isInRange) {
return value;
}
return newInt;
}
</script>
<div class="flex flex-row gap-4 {clazz}" {...$$restProps}>
<RangeSlider name={name} class="basis-3/4" bind:value {min} {max} {step}>
<span class="flex justify-between">
<span class="text-xs">{min}{suffix}</span>
<span class="text-xs">{max}{suffix}</span>
</span>
</RangeSlider>
<span class="basis-1/4 flex flex-row gap-1 items-center">
<input
class="input text-sm w-auto"
type="number"
value={value}
on:input={onInputChanged}
{min}
{max}
{step}
/>
<span>{suffix}</span>
</span>
</div>
>Solution :
Svelte updates the DOM on change. If the new value is outside the valid range, you effectively set value to value, hence the state is determined to have not changed and no update is performed.
You could force an update by first invalidating the variable via a completely different value, e.g.
value = null;
value = valueToSet;
(This might only work with the reactivity model of Svelte 3/4.)