Home > Blockchain >  Dynamically create div with {#each} in Svelte
Dynamically create div with {#each} in Svelte

Time:07-21

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

REPL example

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

REPL example

  • Related