Skip to content

x-for reorders nested templates incorrectly #4911

Open

Description

@rameel

Alpine.js version

3.17.3

Browser and operating system

Chrome, Firefox on Linux

Describe the issue you're experiencing

I found a problem with reordering items in x-for when its direct child is another <template>. It happens with nested x-for and also with nested x-if, even when :key is set.

Clicking Reverse changes the array, but the displayed items end up in the wrong order.

It looks like Alpine moves the template nodes, but not all the elements rendered by the nested templates.

I have a fix for this and will open a PR shortly.

This goes back to Alpine 3.0.0. I tested 22 releases, including the latest patch of each minor version from 3.0 to 3.17. Both examples fail in all tested versions, though the behavior changes:

  • In early versions, no content is rendered.
  • In later versions, the content appears but the initial order is wrong.
  • From 3.15.9 onward, the tested versions render correctly at first, but reverse() breaks the order.

I didn't test every intermediate patch release.

Code snippets to reproduce the issue

<!doctype html>
<html>
<body>
    <div x-data="{
        groups: [
            { key: 'a', values: ['aa', 'ab'] },
            { key: 'b', values: ['ba', 'bb'] },
            { key: 'c', values: ['ca', 'cb'] },
        ]
    }">
        <button @click="groups.reverse()">Reverse</button>

        <template x-for="group in groups" :key="group.key">
            <template x-for="value in group.values" :key="value">
                <div x-text="value"></div>
            </template>
        </template>
    </div>

    <hr>

    <div x-data="{ items: [1, 2, 3] }">
        <button @click="items.reverse()">Reverse</button>

        <template x-for="n in items" :key="n">
            <template x-if="true">
                <template x-if="true">
                    <span x-text="n"></span>
                </template>
            </template>
        </template>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/alpinejs@3.17.3/dist/cdn.min.js"></script>
</body>
</html>

Actual results after one click on each button:

  • First example: aa, ba, bb, ab, ca, cb
  • Second example: 2, 1, 3

Screenshots/screen recordings

No response

How do you expect it to work?

The displayed items should follow the new array order.

In the first example, the groups should be reversed, with each group's children moving together.
Expected order: ca, cb, ba, bb, aa, ab.

In the second example, the elements rendered by the nested x-if templates should move with their items.
Expected order: 3, 2, 1.

Please confirm (incomplete submissions will not be addressed)

  • I have provided easy and step-by-step instructions to reproduce the bug.
  • I have provided code samples as text and NOT images.
  • I understand my bug report will be removed if I haven't met the criteria above.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions