Search code examples
alpine.jsroot-node

Multiple root nodes in Alpine.js


Building a data table with the latest Alpine.js (v3.7.0). Ran into a problem when trying to implement child rows (i.e an additional togglable row under the main/parent row).

Simplified version:

<tbody>
<template x-for="row in currentPageData" :key="row.id">
    <tr>
        <td>foo</td>
        <td>bar</td>
        <td>baz</td>
    </tr>
    <tr>
        <td colspan="3">
            Some additional content
        </td>
    </tr>
</template>
</tbody>

While I'm not getting any errors in the console, the second node (tr) is not rendered. I assume that's because Alpine requires a single root element. Is there any way around it, as wrapping with div is invalid HTML and a tbody wrapper breaks the layout?


Solution

  • Thanks to Alpine templates being rendered server-side I ended up with the following workaround:

    When table has child rows I remove the root tbody and wrap each tr pair with a tbody of its own.

    EDIT (23-9-22):

    As per @NoobnSad's request code in twig:

    {% if not options.enableChildRows %}
    <tbody>
    {% endif %}
    <template x-for="row in currentPageData" :key="row.id">
        {% if options.enableChildRows %}
        <tbody>
        {% endif %}
    <tr>
        {% if options.enableChildRows %}
            {% include datatable.componentPath('childRowToggler') %}
        {% endif %}
        {% include datatable.componentPath('tableCells') %}
    </tr>
    {% if options.enableChildRows %}
    {% include datatable.componentPath('childRow') with {tableHandle:datatable.handle} %}
    </tbody>
    {% endif %}
    </template>
    <template x-if="recordsCount===0">
    {% include datatable.componentPath('notFound') %}
    </template>
    {% if not options.enableChildRows %}
    </tbody>
    {% endif %}