'Svelte3 input validation
Yesterday I was trying to translate a problem I had to solve in React, to Svelte, and I can't figure it out.
The problem is the following:
- I have 3 inputs each one of them holds a percentage.
- The 3 percentages altogether cannot add more than 100.
- I have a fourth input, it's disabled, so it just shows the remaining percentage to 100%
In react is fairly easy, declare a function that takes, the event and a variable to know which input I'm taking the event from. Do the proper validations and done.
Sadly in svelte I have almost 0 experience, and I don't know how to tackle it. This the code so far (spoiler alert it does not even get close to do what is supposed to do). Svelte REPL
Running a console.log to show the value of sp1, inside the function that validates it, and outside the function (before and after the function), shows what I do expect:
- Before the function (before): value in the input
- Inside the function: value validated
- Outside the function (after): value validated
So the validation and assignment of the correct value takes place, nonetheless the input keep showing wrong value (ex: input shows 112 and the value should be 100).
Solution 1:[1]
A more dynamic way to do this would be using arrays.
let inputs = [{
value: 0,
color: 'GRAY'
}, {
value: 0,
color: 'DARKSLATEGRAY'
}, {
value: 0,
color: 'TEAL'
}];
This would also make calculations easier since we can use the array methods. It would also enable us to use each
blocks which remove redundant code. Then we will use a function called validate
and pass the index of the current input to it. Using the input
we can calculate the maximum possible value that can be entered in that input
and set the input
if it crosses that maximum value. This validate
function will be called from the template on the input
event.
Here's the code.
<script>
let total = 100;
let inputs = [{
value: 0,
color: 'GRAY'
}, {
value: 0,
color: 'DARKSLATEGRAY'
}, {
value: 0,
color: 'TEAL'
}];
$: spOthers = total - inputs.map(x => x.value || 0).reduce((a, b) => a + b);
function validate(index) {
let maxInput = total - inputs.map(x => x.value).filter((x, i) => i !== index).reduce((a, b) => a + b);
if (inputs[index].value > maxInput) {
inputs[index].value = maxInput;
}
}
</script>
{#each inputs as {value, color}, i}
<div class='input-container'>
<div class='square' style="background-color: {color}" />
<input type="number" min="0" class='input' bind:value={value} on:input={() => validate(i)} />
</div>
{/each}
<div class='input-container'>
<div class='square' style="background-color: DARKORANGE" />
<input type='number' class='input input-others' bind:value={spOthers} disabled/>
</div>
Note: I have omitted the styles above as there are no changes in them.
Here is a working REPL.
Solution 2:[2]
Nice. You can also do:
$: spOthers = inputs.reduce((a, c, i, inputs) => a + c.value, 0);
function validate(index) {
const delta = spOthers - total;
if (delta > 0) {
inputs[index].value -= delta;
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | nash11 |
Solution 2 | voscausa |