Joe Berthelot
Joe Berthelot

Reputation: 537

Error: {#each} only iterates over array-like objects. -- Javascript & Svelte

<script context="module">
    import GhostContentAPI from '@tryghost/content-api';

    // const api = 'http://localhost/posts';
    const api = new GhostContentAPI({
        url: 'http://localhost',
        key: '95a0aadda51e5d621abd2ee326',
        version: "v3"
    });

    export async function preload({ params, query }) {
        try {
            const response = await api.posts.browse({ limit: 5, fields: 'title, slug' });
            return {
                posts: response
            }
        } catch(err) {
            console.log('Error');
        }
    }
</script>

<script>
    export let posts;
</script>

<svelte:head>
    <title>Blog</title>
</svelte:head>

<h1>Recent posts</h1>
<ul>
    {#each posts as post}
        <li>
            <a rel='prefetch' href='blog/{post.slug}'>{post.title}</a>
        </li>
    {/each}
</ul>

I'm using vanilla JavaScript and Svelte to simply fetch a list of blog posts, which are objects from the Ghost Blog Rest API. The Ghost API function works fine and pulls the correct objects, but the problem begins when trying to use Svelte's {#each} block to display each object because they aren't in an array and I cannot figure out how to fix it. Here's the exact error message in the console:

Error: {#each} only iterates over array-like objects.

Writing a console.log(response) after the const response declaration outputs the attached image, but only if I comment out the {#each} block first.

I'm guessing I simply need to move the 5 objects into an array, but I also don't understand why the console.log above only works when the HTML is commented out.

Console Log Image

Upvotes: 13

Views: 18421

Answers (4)

Irhutchi
Irhutchi

Reputation: 11

I was having a similar issue and stumbled upon this post. It would be nice to see the full JSON repsonse in the original post to give greater context. In my case it turns out I was referring to nested array objects incorrectly. I hope this helps anyone who has a similar issue.

Doesn't Work

 <tbody class="uk-text-left">
    <!-- {@debug calendarEventList} -->
    {#if calendarEventList}
      {#each calendarEventList as event}
        <tr>
            <td>{calendarEventList.items[1].summary}</td>
            <td>{calendarEventList.items[1].start.dateTime}</td>
            <td>{calendarEventList.items[1].end.dateTime}</td>
            <td>{calendarEventList.items[1].creator.email}</td>
            
        </tr>
      {/each}
    {/if}
  </tbody>

Uncaught (in promise) Error: {#each only iterates over array-like objects

Does Work

 <tbody class="uk-text-left">
    <!-- {@debug calendarEventList} -->
    {#if calendarEventList}
      {#each calendarEventList.items as event}
        <tr>
            <td>{event.summary}</td>
            <td>{event.start.dateTime}</td>
            <td>{event.end.dateTime}</td>
            <td>{event.creator.email}</td>
        </tr>
      {/each}
    {/if}
  </tbody>

Example of get request to google calendar api

{
"kind": "calendar#events",
"etag": "\"p334fwehgbta5ve0g\"",
"summary": "Svelte StackOverflow",
"updated": "2022-04-11T10:44:38.077Z",
"timeZone": "Europe/Dublin",
"accessRole": "reader",
"defaultReminders": [],
"nextSyncToken": "CMj8_xxxx_cCEAAHSHDHD8-LRAQ==",
"items": [
    {
        "kind": "calendar#event",
        "etag": "\"3299347666786000\"",
        "id": "5rqm5kq33ghd9tuhsktjhoisdvho",
        "status": "confirmed",
        "htmlLink": "https://www.google.com/calendar/event?eid=Npw",
        "created": "2022-04-11T10:43:53.000Z",
        "updated": "2022-04-11T10:43:53.393Z",
        "summary": "Call Back Customer",
        "creator": {
            "email": "[email protected]"
        },
        "organizer": {
            "email": "[email protected]",
            "displayName": "Svelte StackOverflow",
            "self": true
        },
        "start": {
            "dateTime": "2022-04-11T07:15:00+01:00",
            "timeZone": "Europe/Dublin"
        },
        "end": {
            "dateTime": "2022-04-11T08:15:00+01:00",
            "timeZone": "Europe/Dublin"
        },
        "iCalUID": "[email protected]",
        "sequence": 0,
        "eventType": "default"
    },
    {
        "kind": "calendar#event",
        "etag": "\"3299347756154000\"",
        "id": "78flukdyhjjki16ola",
        "status": "confirmed",
        "htmlLink": "https://www.google.com/calendar/event?eid=NzhjAZw",
        "created": "2022-04-11T10:44:25.000Z",
        "updated": "2022-04-11T10:44:38.077Z",
        "summary": "Maintenance at pharma company x",
        "creator": {
            "email": "[email protected]"
        },
        "organizer": {
            "email": "[email protected]",
            "displayName": "Svelte StackOverflow",
            "self": true
        },
        "start": {
            "dateTime": "2022-04-14T08:00:00+01:00",
            "timeZone": "Europe/Dublin"
        },
        "end": {
            "dateTime": "2022-04-14T09:00:00+01:00",
            "timeZone": "Europe/Dublin"
        },
        "iCalUID": "[email protected]",
        "sequence": 0,
        "eventType": "default"
    }
]

}

Upvotes: 1

RAZ0229
RAZ0229

Reputation: 306

I was facing a similar issue. This happened while working with Firebase Firestore and by comparing the erroneous value with the prototype given in the official svelte documentation, I came to a conclusion.

enter image description here

So I simply used the javascript Object.values() method on the retrieved object and {#each} only iterates over array-like objects error was gone.

Upvotes: 2

user9645391
user9645391

Reputation:

This happens in Dispatching too. Solution is not reassigning array, the solution is something like this :

const array = [];
let newArray = [e.detail, ...array];

Upvotes: 0

Joe Berthelot
Joe Berthelot

Reputation: 537

Changing:

export let posts;

to

export let posts = [];

fixed the issue. Thanks to @Heretic Monkey

Upvotes: 18

Related Questions