I'm trying to dynamically create a 5 divs with a li using {each} in Svelte.
The code below renders the divs and lis but runs the calculate only once and hence gives the same result on each div/li:
let price;
let numberOfYears = 5;
function calculate() {
price = price * 1.04;
}
<form action="">
<label for="price">Price: </label>
<input type="number" bind:value={price} id="price" name="price" />
<button on:click={calculate}>Calculate</button>
{#each { length: numberOfYears } as _, i}
<div style="float: left; width: 19%; border: 1px solid #000000;">
<h2>Year 1</h2>
{calculate()}
<ul>
<li>{price}</li>
</ul>
</div>
{/each}
What I'm after is 5 years with incremental price (price * 1.04)
CodePudding user response:
An alternative approach would be to use old fashioned mathematics to calculate your rates instead.
<script>
let numberOfYears = 5;
let price = 1;
let rate = 1.04;
$: calculate = year => price*Math.pow(rate,year);
</script>
<input type="number" bind:value={numberOfYears} >
<input type="number" bind:value={price} >
<input type="number" bind:value={rate} step=".01">
{#each { length: numberOfYears } as _, i}
<div>
<h2>Year {i}</h2>
<p>{calculate(i)}</p>
</div>
{/each}
here the calculate
function is reactive, so it will generate a new function whenever price or rate changes. You could also write it directly in your brackets or use a {@const}
to inline it more:
{#each { length: numberOfYears } as _, i}
{@const intrest = price*Math.pow(rate,i)}
<div>
<h2>Year {i}</h2>
<!-- with @const -->
<p>{intrest}</p>
<!-- formula directly in the markup -->
<p>{price*Math.pow(rate,i)}</p>
</div>
{/each}
note that my maths might be a bit off, make sure to use the correct formula
CodePudding user response:
Svelte is intended to be declarative, so you should not modify state in {#each}
, instead your data array should contain the fully calculated results (or at least be independent from a shared mutable state).
So declare an array, e.g. prices
and set that in calculate()
, then use its items in the each
.
E.g. something like this:
let prices = [];
function calculate() {
prices = new Array(numberOfYears).fill(price).map((p, i) => p * 1.04**i)
}
You could also use a reactive statement ($:
) to automatically calculate the values whenever a used variable (price
/numberOfYears
) changes;
let price = null;
let numberOfYears = 5;
$: prices = price == null ?
[] : new Array(numberOfYears).fill(price).map((p, i) => p * 1.04**i);