putyourlightson / craft-sprig

A reactive Twig component framework for Craft CMS.
https://putyourlightson.com/plugins/sprig
MIT License
129 stars 9 forks source link

Nested component not getting correct ID from parent #370

Closed petehjfd closed 4 months ago

petehjfd commented 6 months ago

Support Request

Hi Ben

I've got a nested component situation that's not working the way I would exepct and I'm not sure what I'm doing wrong.

The parent component is a 'load more' component, very similar to the example in the cookbook.

I've stripped out some code that's not relevant to the issue:

{% set offset = offset ?? 0 %}

{# Some code to build an array of elements (superTable blocks) here #}

{% set items = allItems|slice(offset, 12) %}

<section id="projects-gallery">
    {% for item in items %}
        <article>
            {# Some code to output the element here #}

            {{ sprig('_components/wishlist-toggle', {'elementId': item.image.id}, {'id': 'wishlist-toggle'}) }}
        </article>
</section>

{# If the total item count is greater than the number that has been displayed #}
    {% if allImages|length > offset + images|length %}
        {# Increments `offset` by the value of `limit` #}
        <button id="load-more-oob" class="btn btn-white" type="button" sprig s-val:offset="{{ offset + limit }}"
            {# Appends all `#projects-gallery article` elements to the `#projects-gallery` element #}
            s-select="#projects-gallery article" s-target="#projects-gallery" s-swap="beforeend"
            {# If this button was clicked then swap it out-of-band #}
            {{ sprig.trigger == 'load-more-oob' ? 's-swap-oob="true"' }}
        >
            Load more
        </button>
    {% else %}
        {# Swaps the button out-of-band with a dummy button that is hidden #}
        <button id="load-more-oob" s-swap-oob="true" style="display: none"></button>
    {% endif %}
{% endfor %}

Inside that component, each item that is 'loaded' has a button that adds the element to a (Verbb) wishlist, very similar to the wishlist example in the cookbook..

{# The value of this input field will be posted to the action #}
<input type="hidden" name="elementId" value="{{ elementId }}">

{% set item = craft.wishlist.item(elementId) %}

{% if item.inList %}
    {# Posts to the `remove` action on click #}
    <button class="bookmark-button" type="btn" sprig s-method="post" s-action="wishlist/items/remove">
        {% include "_svg/bookmark-solid.svg" %}
    </button>
{% else %}
    {# Posts to the `add` action on click #}
    <button class="bookmark-button" type="btn" sprig s-method="post" s-action="wishlist/items/add">
        {% include "_svg/bookmark.svg" %}
    </button>
{% endif %}

For the elements that are loaded on page load, everything works perfectly. However, for the elements that are loaded after clicking the 'Load more' button, the elementId that is passed through to the child component is incorrect. Every element gets the same elementId, which is the id of the last element in the list of elements loaded on page load.

I know nested components can be tricky, but my situation is very similar to the nested components example in the cookbook, so I'm not sure why it's not working. I'm hoping it's something simple!

Any help you can offer would be greatly appreciated.

Many thanks

Plugin Version

2.8.1

bencroker commented 6 months ago

If you can create a simpler example that I can reproduce locally without requiring third-party plugins then I’d be happy to test and advise on what could be improved.

bencroker commented 6 months ago

I also noticed that your for loop appears to be closed in the wrong place. I assume it should be:

    {% for item in items %}
        <article>
            {# Some code to output the element here #}

            {{ sprig('_components/wishlist-toggle', {'elementId': item.image.id}, {'id': 'wishlist-toggle'}) }}
        </article>
    {% endfor %}
bencroker commented 4 months ago

Closing due to inactivity.