I'm messing around with Svelte and the sb-admin-svelte project. I'm working with some sample data from an API in JSON and I have it working so far, but my question is how do I get the key items from the JSON data to automatically parse as a table header in the HTML?
This is what I have so far:
JSON
[
{
"id": 1,
"name": "Leanne Graham",
"username": "Bret",
"email": "[email protected]",
"address": {
"street": "Kulas Light",
"suite": "Apt. 556",
"city": "Gwenborough",
"zipcode": "92998-3874",
"geo": {
"lat": "-37.3159",
"lng": "81.1496"
}
},
"phone": "1-770-736-8031 x56442",
"website": "hildegard.org",
"company": {
"name": "Romaguera-Crona",
"catchPhrase": "Multi-layered client-server neural-net",
"bs": "harness real-time e-markets"
}
},
{
"id": 2,
"name": "Ervin Howell",
"username": "Antonette",
"email": "[email protected]",
"address": {
"street": "Victor Plains",
"suite": "Suite 879",
"city": "Wisokyburgh",
"zipcode": "90566-7771",
"geo": {
"lat": "-43.9509",
"lng": "-34.4618"
}
},
"phone": "010-692-6593 x09125",
"website": "anastasia.net",
"company": {
"name": "Deckow-Crist",
"catchPhrase": "Proactive didactic contingency",
"bs": "synergize scalable supply-chains"
}
},
{
"id": 3,
"name": "Clementine Bauch",
"username": "Samantha",
"email": "[email protected]",
"address": {
"street": "Douglas Extension",
"suite": "Suite 847",
"city": "McKenziehaven",
"zipcode": "59590-4157",
"geo": {
"lat": "-68.6102",
"lng": "-47.0653"
}
},
"phone": "1-463-123-4447",
"website": "ramiro.info",
"company": {
"name": "Romaguera-Jacobson",
"catchPhrase": "Face to face bifurcated interface",
"bs": "e-enable strategic applications"
}
}
...
JS
<script>
import Table from "sveltestrap/src/Table.svelte";
import { onMount } from "svelte";
let users = [];
onMount(async () => {
const res = await fetch(`https://jsonplaceholder.typicode.com/users`);
users = await res.json();
console.log(users);
});
const tableHeading = ["ID", "Name", "Username", "email"];
</script>
<Table bordered responsive>
<thead>
<tr>
{#each tableHeading as heading}
<th>{heading}</th>
{/each}
</tr>
</thead>
<tbody>
{#each users as user}
<tr>
<th scope="row">{user.id}</th>
<td>{user.name}</td>
<td>{user.username}</td>
<td>{user.email}</td>
</tr>
{/each}
</tbody>
</Table>
Which outputs to this:
Which is fine but what I am trying to figure out is how to get the tableHeading
data from the JSON data (e.g. "id", "name" "username", "email
) to automatically populate within the {#each tableHeading as heading}
.
CodePudding user response:
Is this what you want to do? REPL
<script>
import Table from "sveltestrap/src/Table.svelte";
import { onMount } from "svelte";
async function fetchUsers() {
const res = await fetch(`https://jsonplaceholder.typicode.com/users`);
return await res.json();
}
</script>
{#await fetchUsers() then users}
<Table bordered responsive>
<thead>
<tr>
{#each Object.keys(users[0]).slice(0,4) as heading}
<th>{heading}</th>
{/each}
</tr>
</thead>
<tbody>
{#each users as user}
<tr>
<th scope="row">{user.id}</th>
<td>{user.name}</td>
<td>{user.username}</td>
<td>{user.email}</td>
</tr>
{/each}
</tbody>
</Table>
{/await}
But why not automatically populate the table content as well, based on a given number of columns REPL
<script>
import Table from "sveltestrap/src/Table.svelte";
import { onMount } from "svelte";
async function fetchUsers() {
const res = await fetch(`https://jsonplaceholder.typicode.com/users`);
return await res.json();
}
const columns = 4
</script>
{#await fetchUsers() then users}
<Table bordered responsive>
<thead>
<tr>
{#each Object.keys(users[0]).slice(0,columns) as heading}
<th>{heading}</th>
{/each}
</tr>
</thead>
<tbody>
{#each users as user}
<tr>
{#each Object.values(user).slice(0,columns) as value, index}
{#if index===0}
<th scope="row">{value}</th>
{:else}
<td>{value}</td>
{/if}
{/each}
</tr>
{/each}
</tbody>
</Table>
{/await}
For the inner #each loop inside the table body the new svelte:element could be used instead (but not really the better option in this case)
{#each Object.values(user).slice(0,columns 1) as value, index}
<svelte:element this={index === 0 ? 'th': 'td'}
scope={index === 0 ? 'row' : undefined}
>
{value}
</svelte:element>
{/each}
But a more flexible and convenient way would be to populate everything, like you already did, by a defined tableHeading and fill the table body based on that. Like this unwanted values can simply be omitted and the order easily changed REPL
<script>
import Table from "sveltestrap/src/Table.svelte";
import { onMount } from "svelte";
async function fetchUsers() {
const res = await fetch(`https://jsonplaceholder.typicode.com/users`);
return await res.json();
}
const tableHeading = ["ID", "Name", "Website", "email", "Username", "Phone"];
</script>
{#await fetchUsers() then users}
<Table bordered responsive>
<thead>
<tr>
{#each tableHeading as heading}
<th>{heading}</th>
{/each}
</tr>
</thead>
<tbody>
{#each users as user}
<tr>
{#each tableHeading as key, index}
{@const k = key.toLowerCase()}
{#if index===0}
<th scope="row">{user[k]}</th>
{:else}
<td>{user[k]}</td>
{/if}
{/each}
</tr>
{/each}
</tbody>
</Table>
{/await}