Как сделать компонент AlpineJS "re-render" после замены HTMX
Я пытаюсь интегрировать Django + AlpineJS + HTMX. Все идет хорошо, но когда я пытаюсь подменить HTML, который уже является частью компонента AlpineJS
Если я меняю местами html, компонент отображается правильно только после второй замены.
шаблон
<div id="cart-row" x-data="{selectedOrderItem: {{item_id|default:'null'}} }">
<div id="cart-holder">
<table id="cart">
<thead>
<tr>
<th style="width: 10%">CANT</th>
<th>Product</th>
<th style="width: 15%">TOTAL</th>
</tr>
</thead>
<tbody>
{% for item in items %}
<tr
id="product{{item.product.id}}"
:class="{ selectedOrderItem: selectedOrderItem == {{item.id}} }"
@click="selectedOrderItem = {{item.id}};"
>
<td>{{item.quantity}}</td>
<td>{{item.product.name}}</td>
<td>{{item.get_price}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<div id="right-menu">
<div id="table-buttons" hx-swap-obb="true">
{% for item in items %}
<div class="" x-cloak x-show="selectedOrderItem == {{item.id}}">
<button
class="addButton"
hx-trigger="click"
hx-target="#cart-row"
hx-swap="outerHTML"
hx-post="{% url 'add_to_cart' idOrder=order.id idProduct=item.product.id %}?cartAction=1"
>
+ {{item.id}}
</button>
</div>
{% endfor %}
</div>
</div>
Например, если я нажимаю кнопку "Добавить в корзину", div #cart-row
меняется местами, но привязка :class="{ selectedOrderItem: selectedOrderItem == {{item.id}} }"
срабатывает только во второй раз. Как будто AlpineJS не понимает, что содержимое поменялось местами.
Есть ли способ заставить весь компонент "повторно отображаться / повторно инициализироваться"? Или какой правильный способ сделать эту подмену?
Проблема заключается в том, что вы не включаете в запрос HTMX данные о состоянии, которое имеет этот компонент Alpine.js (selectedOrderItem
). Поэтому, когда HTMX поменяет местами весь компонент, он потеряет значение selectedOrderItem
во время процесса. Нам нужно отправить эту переменную на бэкенд и включить ее в шаблон. Самый простой способ добавить дополнительные данные в запрос HTMX - использовать скрытый элемент ввода с x-model
на нем для синхронизации данных, а затем использовать hx-include
для добавления их в запрос. Поместите это в любое место внутри компонента:
<input type="hidden" name="selected_order_item" x-model="selectedOrderItem">
И модифицируйте кнопку:
<button
class="addButton"
hx-trigger="click"
hx-target="#cart-row"
hx-swap="outerHTML"
hx-include="[name='selected_order_item']"
hx-post="{% url 'add_to_cart' idOrder=order.id idProduct=item.product.id %}?cartAction=1"
>
Теперь на бэкенде мы можем получить доступ к нему через request.POST
, например:
context={
"order": order,
"items": items,
"selectedOrderItem": request.POST.get("selected_order_item", "null")
}
После этого в x-data
появится выбранный пункт заказа.
x-data="{selectedOrderItem: {{selectedOrderItem}} }"