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>
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.)