Macsupport
Macsupport

Reputation: 5444

Svelte - switching between two input values using a checkbox

I'm new to svelte and I am trying to figure out how to change a default value of an input when a checkbox is checked and also use this changed value in a calculation.

The code I have works:

 <label> {#if yes}
SI Units to US Units
{:else}
    US Units to SI units
{/if}
<input type=checkbox bind:checked={yes}>
</label>


{#if yes}
<input bind:value={siValue}>        
{:else}
<input bind:value={usValue}>        
{/if}

{#if yes}
<span>{((siValue / factor)).toFixed(2)}</span>
{:else}
<span>{((usValue * factor)).toFixed(2)}</span>
{/if}

What I would like to do is use just one input and change the default value but also be able to manually change the input value as well, but I'm having trouble getting it to work. The value changes but when I try and change the numeric value manually, the calculation does not work.

Here is that code:

 <input value={yes ? siValue : usValue} on:input="{e => setUnitVal(e.target.value)}">


<script>
let yes = false;
let siValue = '';
let usValue = '';

function setUnitVal(value) {
    siValue = +value;
    usValue = +value;
}   

</script>   

Upvotes: 0

Views: 1090

Answers (2)

nash11
nash11

Reputation: 8680

Here's another way to do the same. You can use the JS label syntax $: to make the values of usValue and siValue reactive. We will not place $: directly on usValue and siValue since it will create a cyclical dependency since usValue depends on siValue and vice versa. Instead we will place it on the yes variable and conditionally assign usValue and siValue.

Then in the template, all we need to do is bind the input value and span to their respective variables while the JS label syntax takes care of the calculation for us.

<script>
    let yes = false;
    let factor = 1.2;
    let siValue = '';
    let usValue = '';
    $: yes ? usValue = (siValue / factor).toFixed(2) : siValue = (usValue * factor).toFixed(2);
</script>

<label>
    {#if yes}
        SI Units to US Units
    {:else}
        US Units to SI units
    {/if}
    <input type=checkbox bind:checked={yes}>
</label>

{#if yes}
    <input bind:value={siValue}>
    <span>{usValue}</span>
{:else}
    <input bind:value={usValue}>
    <span>{siValue}</span>
{/if}

Here is an example on the Svelte REPL.

Upvotes: 1

will_wow
will_wow

Reputation: 301

Edited after talking in the comments

Since assigning to an object in an array triggers a re-render, you could conditionally calculate the new siValue and usValue for a given unit based on the yes flag, and update the values for that unit. That'll let you update both the SI and US values as the user types, so they can freely switch which value goes in the inputs.

<script>
  let yes = false;

  const units = [{
    "factor": "6.614",
    "siValue": "66",
    "usValue": "10"
  }, {
    "factor": "97.95",
    "siValue": "100",
    "usValue": "1"
  }];

  function setUnitVal(value, index) {
    const { factor } = units[index];

    units[index].siValue = yes ? value : (value * factor).toFixed(2);
    units[index].usValue = yes ? (value / factor).toFixed(2) : value;
  }
</script>

<label>
  {#if yes}SI Units to US Units{:else}US Units to SI units{/if}
  <input type="checkbox" bind:checked={yes} />
</label>

{#each unitValues as { usValue, siValue, factor}, i}    
  <div>
    <input
      value={yes ? siValue : usValue}
      on:input={e => setUnitVal(e.target.value, i)} />

    {#if yes}
      <span>{usValue}</span>
    {:else}
      <span>{siValue}</span>
    {/if}
  </div>
{/each}

If you wanted to be able to revert to defaults, then you could clone that units array on load, and reset to the original values at will, like so:

<script>
  import _ from 'lodash'

  const units = [...];

  let unitValues = [];

  function resetUnitValues() {
    unitValues = _.cloneDeep(units);
  }

  resetUnitValues();
</script>

...

<button on:click={resetUnitValues}>Clear</button>

Here's all that in the Svelte REPL: https://svelte.dev/repl/aed32ef30b02448aafd173e0baf681b0?version=3.12.1

Hope that helps!

Upvotes: 0

Related Questions