Home > Blockchain >  Svelte App Won't Render my Data in the Browser
Svelte App Won't Render my Data in the Browser

Time:07-14

I'm pretty new to Svelte and I'm trying to render my data object in the browser. I'm not sure what's going on as the backend seems to be okay and I'm able to print the data object in the console.

I have a backend flask api that reads the following url

https://api.le-systeme-solaire.net/rest/bodies/

That's up and working fine. If you look it up you can see what the json looks like

This is the top half of my index.svelte file:

<script>

let data = []

async function initFetchSolarSystemData() {
 let response = await fetch("http://127.0.0.1:5000/solar-system/gravity");
 data = await response.json();

console.log("data", data)
console.log(["id", data.bodies[0].id])
console.log(["gravity", data.bodies[0].gravity])
console.log(["bodies", data.bodies.length])
}

initFetchSolarSystemData()

</script>

So when it runs, I can see values in the console like:

['id', 'lune']
['gravity', 1.62]
'bodies', 287]

So that seems to be working fine as well. Here is the bottom portion of the file where I believe the error is stemming from:

<section>

    {#if data.length}
        {#each data.bodies as item}

            <div >
              <h1 id="item">
                {item.gravity}
              </h1>
            </div>

        {/each}
    {/if}

</section>

When the I run the script, I get no errors in the console. Nothing renders. If I replace this line:

 {#if data.length}

with

{#if data.bodies.length}

I get:

Cannot read properties of undefined (reading 'length')

Which I'm confused about because these values are being read earlier above in the file.

I think I'm missing something here, and any help would be immensely appreciated.

CodePudding user response:

Problem

This looks like a classical problem with async execution logic — when the {#if data.length} gets evaluated, the "data" variable is still not populated as the async function that does that is not awaited.

Solution

This can be solved by wrapping the <section>…</section>'s content with Svelte's await block as follows:

  {#await initFetchSolarSystemData()}
    <p>Loading…</p>
  {:then data}
    …
  {:catch error}
    <p>Uh oh, an error.</p>
  {/await}

Also, to facilitate it:

  1. Modify the initFetchSolarSystemData() function to return the "data".
  2. Remove the initFetchSolarSystemData() call from your <script>…</script> part.
  3. Change the {#if data.length} to {#if data.bodies.length} since it looks like the data variable is actually expected to hold an Object, not an Array.

Demo

https://codesandbox.io/embed/lively-river-dni3l6?fontsize=14&hidenavigation=1&theme=dark


I hope this answers your question. =)

CodePudding user response:

The real issue here is that you are mixing types.

With {#if data.length}, you are checking the length property of data, which initially is an array of length 0, so it doesn't render the if block.

Then in your function you assign an object to data instead of an array as it was before. Now data.length will be undefined because your object doesn't have a property 'length' and your if block doesn't render.

You are getting close with your idea of checking data.bodies.length because that is indeed the array you want to check. But you get into an error because your initial array doesn't have bodies so you can't read the length of it.

2 Solutions

A first solution would be the initialize data to be similar to what you expect from the API:

let data = { bodies: [] }

then you can do {#if data.bodies.length}

Another solution is to actually only use the bodies part:

const result = await fetch(...).then(res => res.json());
data = result.bodies;

and then data is an array with all your bodies, so use {#each data as item} instead.

  • Related