Query symbol from code - bug

As you know, when you would like to access a data from builder, by default the upper one is the returned one.

In my code I have 2 symbols:

<Container>
        <BuilderComponent
          model="symbol"
          data={localizedData(filteredData?.data, true)}
        />
        <BuilderComponent
          model="symbol"
          options={{ query: { id: 'dea1ff8b5458485b91c0eb55ab7cf189' } }}
          data={{
            leftData: leftData,
            rightData: rightData,
            locale: locale,
          }}
        />
</Container>

And this way I am passing the data to the symbol.

This is the order in the editor. (The customer-story-promo is the bottom one in the code, where I query by id)

The issue is:

The bottom one is not displaying correctly, but if I switch the order between the two data in the editor:

This way the bottom one correctly displayed.
Why?

Looks like 2 same type of symbol on one page is buggy, if I delete any of these, works properly, but if both are there, something goes wrong
Link to these 2 symbol:

Here is the full code to try out yourself, this is very important, please let me know:

import React from 'react'
import { BuilderComponent, Builder, builder } from '@builder.io/react'
import { useRouter } from 'next/router'



export async function getStaticPaths() {
  const pages = await builder.getAll('barion-userstory-data', {
    options: { noTargeting: true },
    limit: 99999,
    omit: 'data.blocks',
  })

  const paths = pages.map((post) => ({
    params: { id: post.data.name },
  }))

  return {
    paths: paths,
    fallback: true,
  }
}

export async function getStaticProps({ params, locale }) {
  if (locale == 'default') {
    return {
      props: {
        article: null,
        navbar: null,
        footer: null,
        subfooter: null,
      },
      revalidate: 5,
    }
  }

  const filteredData =
    (await builder
      .get('barion-userstory-data', {
        query: {
          name: params.id,
        },
      })
      .toPromise()) || null

  let enumlocalization =
    (await builder
      .get('enum-type-localization', {
        options: {
          includeRefs: true,
          noTraverse: false,
          noTargeting: true,
          query: {
            name: 'data',
          },
        },
      })
      .promise()) || null

  const hero =
    (await builder
      .get('hero-data', {
        query: {
          id: '32f148657e2646be8562eb4e6ebfa190',
        },
      })
      .toPromise()) || null
  const leftData =
    (await builder
      .get('barion-userstory-data', {
        query: {
          id: 'bca70ed951ae400995c38d8622da2d18',
        },
      })
      .toPromise()) || null
  const rightData =
    (await builder
      .get('barion-userstory-data', {
        query: {
          id: 'e54dacffe24f4cfb823c471c4616c4a6',
        },
      })
      .toPromise()) || null

  console.log(leftData)
  console.log(rightData)

  return {
    props: {
      filteredData,
      enumlocalization: enumlocalization.data,
      hero,
      leftData,
      rightData,
    },
    revalidate: 5,
  }
}

const CustomerStoryDetail = ({
  filteredData,
  enumlocalization,
  hero,
  leftData,
  rightData,
}) => {
  const { locale } = useRouter()

  const localizedCountry = (enuma) => {
    return enumlocalization?.country.find((item) => item.key.type == enuma.type)
      ?.value?.[locale]
  }
  const localizedIndustry = (enuma) => {
    return enumlocalization?.industry.find(
      (item) => item.key.type == enuma.type
    )?.value?.[locale]
  }
  const localizedSolution = (enuma) => {
    return enumlocalization?.solution.find(
      (item) => item.key.type == enuma.type
    )?.value?.[locale]
  }

  const localizedData = (data, isDetail = false) => {
    return {
      backgroundImage: data?.backgroundImage,
      backgroundImageAltText: data?.backgroundImageAltText?.[locale],
      detail: {
        ...data?.detail,
        description: data?.detail?.description?.[locale],
        descriptionExplanation: data?.detail?.descriptionExplanation?.[locale],
        employees: data?.detail?.employees?.[locale],
        qa: data?.detail?.qa?.[locale],
      },
      industry: localizedIndustry(data?.industry),
      country: localizedCountry(data?.country),
      solution: data?.solution.map((sol) => localizedSolution(sol.solution)),
      logo: data?.logo,
      name: data?.name,
      threeGridList: data?.threeGridList?.[locale],
      threeGridName: data?.threeGridName?.[locale],
      title: data?.title?.[locale],
      isDetail: isDetail,
    }
  }

  return (
    <div style={{ marginTop: '110px', paddingBottom: '40px' }}>
        <BuilderComponent
          model="symbol"
          options={{ query: { id: 'd0b1658f80c94928af1b96b4877ca9c9' } }}
          data={localizedData(filteredData?.data, true)}
        />
        <BuilderComponent
          model="symbol"
          options={{ query: { id: 'dea1ff8b5458485b91c0eb55ab7cf189' } }}
          data={{
            leftData: leftData,
            rightData: rightData,
            locale: locale,
          }}
        />
        <BuilderComponent
          model="hero"
          data={{
            result: hero,
            locale: locale,
          }}
        />
    </div>
  )
}

export default CustomerStoryDetail

Hey @radikris ! Great question! I plan to author a forum post on just this issue in the next few days, but in the meantime I have a quick fix for you.

Generally, we recommend models to have one <BuilderComponent /> entry per page, as they should mostly be set up to address a single use case. Because of this, our SDK tries to optimize API calls when fetching content entries from the same model.

However, depending on your set up there are might be some cases where you might want different content entries from the same model. Symbols is a good example of this. There are a number of ways you could get around this SDK optimization, but the most straight forward is to pass a key value in the options prop so that the SDK can easily differentiate the calls being made (I passed the same ID, but it could really be anything). I have updated your code below, this should fix the issue, check it out and see if it works for you!

<Container>
        <BuilderComponent
          model="symbol"
          data={localizedData(filteredData?.data, true)}
        />
        <BuilderComponent
          model="symbol"
          options={{ key: 'dea1ff8b5458485b91c0eb55ab7cf189', query: { id: 'dea1ff8b5458485b91c0eb55ab7cf189' } }}
          data={{
            leftData: leftData,
            rightData: rightData,
            locale: locale,
          }}
        />
</Container>
1 Like

Hey Tim!

Thanks for the tip, now this is working, I have only 1 issue and can not make it happen:

Here is the symbol I want to use in my code:

And here is how I try to render it:

<BuilderComponent
                  model="hero"
                  options={{
                    query: 'c9efded2557f441d928968649ed63997',

                    key: 'tophero',
                  }}
                  data={{
                    result: {
                      results: [tophero],
                    },
                    locale: locale,
                  }}
                />

where tophero is earlier fetched:

  let tophero =
    (await builder
      .get('hero-data', {
        query: {
          id: '7de8be4731ec4ea69e532adc4e23c095',
        },
      })
      .promise()) || null

But on the page the symbol:

So the data is there (I added the data.id to the paragraph above), but the builder block is no content, I guess something is wrong with the custom js code in the symbol, can you please check that out?

I believe that question is the same thread as you have here: BuilderComponent symbol data reference binding - #6 by TimG

I have answered there so we can continue the conversation that thread. Thanks!

1 Like