Cannot get value form JSON object in a sveltekit loop

I am using SvelteKit to pull a Prismic object. If I query a single document, I can render the data out fine. However, if I query everything and try to itemize it out in a loop, I am unable to extract the text value from the object.

Stringifying the object, I can see the data I want:

<pre>{ JSON.stringify(results, null, 2) }</pre> 

allows me to see the data

[
  {
    "type": "accounts",
    "data": {
      "created_at": "2021-08-25T05:00:00+0000",
      "name": [
        {
          "type": "heading2",
          "text": "John",
          "spans": []
        }
      ],
      "last_name": [
        {
          "type": "heading2",
          "text": "Doe",
          "spans": []
        }
      ],
    }
  },
  {
    "type": "accounts",
    "data": {
      "created_at": "2021-08-25T05:00:00+0000",
      "name": [
        {
          "type": "heading2",
          "text": "Jane",
          "spans": []
        }
      ],
      "last_name": [
        {
          "type": "heading2",
          "text": "Rey",
          "spans": []
        }
      ],
    }
  },
]

I am trying to get the last_name from the loop, ie Doe and Rey

{#each results as account}   
  <li>{ account.data.last_name }</li>    
{/each}

sends back an object. and

{#each results as account}
  <li>{ account.data.last_name.text }</li>
{/each}

throws an undefined error. I know it has something to with the name and last_name being in the brackets. I just don't know how to extract those in the loop.

I've tried:

account.data.last_name[0]
account.data.last_name["text]
account.data.last_name[0].text

and 20 more iterations of that. I feel I am missing something incredibly obvious here.

Hi @carey,

Thanks for posting this question, and welcome to the Prismic community!

In your API response, last_name and first_name are both Rich Text objects. That means they both have a special structure to allow for formatting. Of course, in your case, there's no formatting, so it just looks a little confusing. But no worries, there are lots of ways to work with this.

First of all, for all JavaScript-based languages, we provide a basic templating kit, which includes helpers for working with Rich Text objects. The kit is called prismic-dom.

You can install it:

npm install prismic-dom

Then import it:

import PrismicDom from "prismic-dom"

Then, you can use it like this in your code snippet:

PrismicDom.RichText.asText(last_name)
// This will output the last name as plain text

PrismicDom.RichText.asHTML(last_name)
// This will output the last name as HTML (in this case, as an h2)

Note that if you output Rich Text as HTML, you need to use Svelte's {@html } block to render it:

{@html PrismicDom.RichText.asHtml(last_name)}

You can also access the last_name text directly (as you attempted to do), but we don't really recommend this. Instead, if you don't need formatting and you don't want to use prismic-dom, you can use the Key Text field for your name and last_name. Key Text just returns text on the API — no object, and no formatting.

I've put most of this into an example, here:

I hope this helps. Please let me know if you have any more questions!

Sam

Thanks for the detailed response.
Ive tried both if the options in the example. Still getting errors.

Ideally, I would like to use the asText method. So pulling the PrismicDom"

import PrismicDom from 'prismic-dom';

...

<ul>
  {#each results as account}
     <li>{ PrismicDom.RichText.asText(account.data.last_name) }</li>
  {/each}
</ul>

which errors out with:

Cannot read property 'map' of undefined
...
at Object.asText (/.../svelte-prismic/node_modules/prismic-dom/dist/prismic-dom.min.js:1:4820) at index.svelte:24:35

Moving to the asHtml option, same as aboev except swapping the methods

<ul>
  {#each results as account}
    <li>{@html PrismicDom.RichText.asHtml(account.data.last_name) }</li>
  {/each}
</ul>

errors with:
Cannot read property 'reduce' of undefined
TypeError: Cannot read property 'reduce' of undefined at Function.value (/../svelte-prismic/node_modules/prismic-dom/dist/prismic-dom.min.js:1:9715)

and last:

{#each results as account}
  <li>{ account.data.last_name[0].text }</li>
{/each}

throws:
Cannot read property '0' of undefined

The last is the one that is the most strange because I know htere is a 0 index, based on the JSON stringify output.

FWIW if I query a specific page by UID, the @html ... asHtml() method works perfectly fine.

Could this be a package version issue?

Hi @carey,

Thanks for the extra detail. Can you tell me your repo name? (You can send it in a DM if you like.) This looks to me like it might be an issue with the content models. It could be that account.data.last_name is undefined for one of the results, which is causing an error.

Sam

Hey @carey,

Thanks for sending your repo name in the DM. I don't see an obvious problem in the repo. Could you send me the code of the entire component? In particular, I'm interested to see the query and how you're structuring your props. (I'm guessing you're returning props from the load() function?) Again, feel free to send in the DM.

Sam

Hey @samlittlefair

Ive pushed my code to github so you can see how Im structuring everything:

I am using the following guide:

Hopefully this helps!

Hey @carey,

That helps a lot. It should work if you replace the <script> tag in /src/index.svelte with this:

<script context="module">
	import Client from './../../utils/client';
	import PrismicDom from 'prismic-dom';
	import Prismic from '@prismicio/client'

	export async function load() {
		const document = await Client.query(Prismic.Predicates.at("document.type", "accounts"));
		return {
			props: {
				document,
			}
		};
	}
</script>

The issue is that your results includes all documents, including your timezone. The timezone doesn't have a last_name, so it errors.

To query documents by type, use Client.query(Prismic.Predicates.at("document.type", "accounts")). To learn more about predicate queries, you can check out our Rest API docs. (Though most people only ever need to use predicates to query by type, so we're adding getByType() in our next version of the Client package.)

Let me know if that helps, or if you have any more questions. I'm off this afternoon, but I'll be back on Monday.

Sam

1 Like

Hey Sam,

That got it. I had previously tried to query just the accounts but kept getting an error on that as well. This is working now. Thanks so much for all the help!

I will update SO with this answer as well.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.