compiler icon indicating copy to clipboard operation
compiler copied to clipboard

Cannot use variable values as slot names in loop

Open spacedawwwg opened this issue 2 years ago • 9 comments

Astro Info

Astro                    v3.0.10
Node                     v20.5.1
System                   Linux (x64)
Package Manager          npm
Output                   static
Adapter                  none
Integrations             @astrojs/vue

If this issue only occurs in one browser, which browser is a problem?

No response

Describe the Bug

I have tried to use variable values as slot names but it isn't working (see below).

NOTE: I've simplified my use case here for code example only - I do have a valid use case for sending HTML to slots from outside the Example component (tables with HTML content)

This is a simple Vue component using named slots based on values in the props.

<script lang="ts" setup>
export interface Props {
  items: {
    id: string;
  }[];
}

defineProps<Props>();
</script>

<template>
    <template v-for="item of items">
      <div
        v-if="$slots && $slots[item.id]"
      >
        <slot :name="item.id" />
      </div>
    </template>
</template>

This is an example of me using the above vue component within an astro file to try populate slots with a mapped value.

---
const items = [
  { id: "1"},
  { id: "2"},
  { id: "abc"}
];
---
<Example items={items}>
  {items.map(({ id }) => <p slot={id}>{id}</p>)}
</Example>

Unfortunately I'm being hit with:

image

I have logged the id and it it is defined... just not when used as the slot name

What's the expected result?

I'd expect astro to use the value to populate the named slot in the child component. with the output:

<div>
 <p>1</p>
</div>
<div>
 <p>2</p>
</div>
<div>
 <p>abc</p>
</div>

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-vqaya3

Participation

  • [ ] I am willing to submit a pull request for this issue.

spacedawwwg avatar Sep 15 '23 15:09 spacedawwwg

So I've also tried below...

this no longer errors as currentIndex is set in the code fence.

The console.log(currentIndex) within the loop logs the correct index but the value used by the slot attribute is always 0 (its as if slot completely ignores all loop values)

---
const items = [
  { id: "1"},
  { id: "2"},
  { id: "abc"}
];
let currentIndex = 0;
---
<Example items={items}>
  {items.map(({ id }, index) => {
    currentIndex = index;
    console.log(currentIndex);
    return (<p slot={items[currentIndex].id}>{id}</p>)
  })}
</Example>

spacedawwwg avatar Sep 19 '23 13:09 spacedawwwg

If you paste the original example in https://live-astro-compiler.vercel.app, you can see it's generated as (formatted for readability):

const items = [{ id: '1' }, { id: '2' }, { id: 'abc' }]

return $$render`${$$renderComponent(
  $$result,
  'Example',
  Example,
  { items: items },
  {
    [id]: () =>
      $$render`${items.map(
        ({ id }) => $$render`${$$maybeRenderHead($$result)}<p>${id}</p>`
      )}`
  }
)}`

The 5th parameter is the slots object. Looks like it's not generating the slots right. I'm not sure if it's possible to fix this in the compiler, but I'll move it there at the mean time as it's a compiler issue.

bluwy avatar Sep 26 '23 13:09 bluwy

If you paste the original example in https://live-astro-compiler.vercel.app, you can see it's generated as (formatted for readability):

const items = [{ id: '1' }, { id: '2' }, { id: 'abc' }]

return $$render`${$$renderComponent(
  $$result,
  'Example',
  Example,
  { items: items },
  {
    [id]: () =>
      $$render`${items.map(
        ({ id }) => $$render`${$$maybeRenderHead($$result)}<p>${id}</p>`
      )}`
  }
)}`

The 5th parameter is the slots object. Looks like it's not generating the slots right. I'm not sure if it's possible to fix this in the compiler, but I'll move it there at the mean time as it's a compiler issue.

yeah, so it feels like while processing the map in the compiler, if it detects slot attributes break up the map into something like:

const items = [{ id: '1' }, { id: '2' }, { id: 'abc' }]

return $$render`${$$renderComponent(
  $$result,
  'Example',
  Example,
  { items: items },
  {
    ['1']: () => $$render`${$$maybeRenderHead($$result)}<p>1</p>`,
    ['2']: () => $$render`${$$maybeRenderHead($$result)}<p>2</p>`,
    ['abc']: () => $$render`${$$maybeRenderHead($$result)}<p>abc</p>`
  }
)}`

spacedawwwg avatar Sep 27 '23 21:09 spacedawwwg

I'm not sure how we could fix this. In this case, the key of the slot render function is derived from a value defined inside the scope of the map function, and the compiler can't really tap into the items array and generate render functions of for each value like in your last comment.

MoustaphaDev avatar Dec 19 '23 11:12 MoustaphaDev

Reopening this as we've reverted the fix made in https://github.com/withastro/compiler/pull/963, due to unexpected regressions that it caused unfortunately. I'll be reworking this in the near future.

MoustaphaDev avatar Feb 06 '24 15:02 MoustaphaDev

Any movement on this @MoustaphaDev ?

spacedawwwg avatar Oct 30 '24 19:10 spacedawwwg

Nope @spacedawwwg, I didn't get to contribute to Astro in the last few months.

I don't recall the details, but my conclusions after further investigating this for a few days at the time was that it's not possible, but I may revisit this when I get back on board 😄

MoustaphaDev avatar Nov 06 '24 12:11 MoustaphaDev

LGTM

sangrepura avatar Mar 27 '25 10:03 sangrepura

LGTM

I don't think there is any WIP. They had to revert the original work caused regressions.

spacedawwwg avatar Apr 01 '25 08:04 spacedawwwg