Reputation: 5444
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
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
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