1

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

2
  • Please add some code which you already tried, I'm afraid nobody will write the code for you... Commented Sep 27, 2019 at 8:12
  • 2
    The code is already provided in the link "Svelte REPL" I tought it was clearly visible. Commented Sep 27, 2019 at 9:42

2 Answers 2

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks! I really like the solution, this is exactly what I was searching for :)
0

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;   
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.