Циклы и коллекции

HTMX предлагает мощные возможности для работы с динамическими интерфейсами, и одна из ключевых задач — это эффективная манипуляция коллекциями данных. Под коллекциями можно понимать как списки элементов на странице, так и более сложные структуры данных, такие как таблицы или списки с пагинацией. В работе с коллекциями часто возникает потребность в циклах — механизмах, позволяющих пройти по элементам коллекции и отобразить их в нужном формате.

Рендеринг коллекций с использованием HTMX

Одним из наиболее часто используемых способов работы с коллекциями в HTMX является динамическое создание элементов на основе данных. Для этого можно использовать стандартный HTML, обогатив его аттрибутами HTMX, такими как hx-get, hx-target, hx-swap и другие.

Пример: вывод списка элементов

Рассмотрим ситуацию, когда необходимо отобразить список товаров. Сервер отправляет данные в формате JSON, и на клиенте нужно динамически сгенерировать HTML для каждого товара.

<div hx-get="/products" hx-trigger="load" hx-target="#product-list">
  <div id="product-list">
    <!-- Здесь будут отображаться товары -->
  </div>
</div>

Сервер отвечает JSON-списком товаров:

[
  {"id": 1, "name": "Товар 1", "price": 100},
  {"id": 2, "name": "Товар 2", "price": 150}
]

С использованием HTMX можно отобразить этот список, создав шаблон на сервере, который будет использовать данные из JSON для генерации HTML.

<ul>
  {{#each products}}
    <li>{{name}} - {{price}} руб.</li>
  {{/each}}
</ul>

Когда клиент делает запрос на сервер (с атрибутом hx-get), он получает HTML-код для списка товаров, и HTMX вставляет его в элемент с ID product-list. Это позволяет динамически обновлять страницу, не перезагружая её полностью.

Циклы на стороне клиента

HTMX также предоставляет возможность использовать циклы на клиенте, что полезно, когда сервер отправляет данные в виде массива объектов, а задача состоит в том, чтобы на лету отобразить эти данные в виде динамической коллекции. Для этого можно использовать атрибут hx-swap в сочетании с элементами DOM, такими как <template> или кастомные компоненты.

Пример: рендеринг коллекции через шаблон

Предположим, что сервер отправляет данные о коллекции продуктов, и нужно отобразить их в виде карточек. В этом случае можно использовать HTMX в сочетании с шаблонизатором:

<div id="product-list" hx-get="/products" hx-trigger="load" hx-swap="outerHTML">
  <template id="product-template">
    <div class="product-card">
      <h3>{{name}}</h3>
      <p>{{price}} руб.</p>
    </div>
  </template>
</div>

Здесь <template> содержит шаблон, который будет копироваться и вставляться в DOM каждый раз, когда данные будут получены с сервера. В случае с HTMX данные заменяются на основе динамических значений, переданных через JSON или другой формат.

Работа с пагинацией

Пагинация — еще один важный аспект работы с коллекциями. В современных веб-приложениях часто возникает необходимость загружать данные порциями, особенно когда речь идет о больших коллекциях, например, о списках товаров, сообщений или комментариев.

HTMX упрощает работу с пагинацией с помощью динамической подгрузки контента. Обычно это реализуется через кнопку «Загрузить еще» или автоматическую подгрузку данных при прокрутке.

Пример: пагинация с HTMX

Предположим, что сервер отправляет данные порциями:

<div id="product-list" hx-get="/products?page=1" hx-trigger="load" hx-target="#product-list">
  <!-- Здесь будут отображаться товары -->
</div>

<button hx-get="/products?page=2" hx-target="#product-list">Загрузить еще</button>

На сервере мы обрабатываем параметр page и отправляем нужные товары для каждой страницы. Когда пользователь нажимает кнопку «Загрузить еще», HTMX делает новый запрос и обновляет содержимое в элементе с ID product-list.

Такой подход позволяет эффективно работать с большими данными, подгружая их только по мере необходимости.

Добавление, удаление и обновление элементов коллекции

HTMX также предоставляет возможности для динамического добавления, удаления и обновления элементов в коллекции, что является важным аспектом взаимодействия с динамическими списками.

Пример: добавление элемента в коллекцию

Предположим, что у нас есть форма для добавления нового продукта:

<form hx-post="/add-product" hx-target="#product-list" hx-swap="beforeend">
  <input type="text" name="name" placeholder="Название продукта">
  <input type="number" name="price" placeholder="Цена">
  <button type="submit">Добавить</button>
</form>

Когда пользователь отправляет форму, HTMX делает POST-запрос на сервер. Сервер, в свою очередь, добавляет новый товар и отправляет обновленный список товаров или только новый элемент. HTMX обновляет коллекцию, вставляя новый товар в конец списка.

Пример: удаление элемента из коллекции

Для удаления элемента из списка можно использовать аналогичный подход. На странице будут отображаться товары с кнопками удаления:

<ul>
  {{#each products}}
    <li>
      {{name}} - {{price}} руб.
      <button hx-delete="/delete-product/{{id}}" hx-target="#product-list">Удалить</button>
    </li>
  {{/each}}
</ul>

Когда пользователь нажимает кнопку «Удалить», HTMX отправляет запрос на сервер с параметром id товара. Сервер удаляет товар и возвращает обновленный список. HTMX автоматически обновляет DOM, удаляя соответствующий элемент.

Обновление элементов коллекции

Чтобы обновить элемент коллекции, можно использовать атрибут hx-put или hx-patch. Например, для обновления информации о продукте:

<div hx-put="/update-product/{{id}}" hx-target="#product-{{id}}" hx-swap="outerHTML">
  <h3>{{name}}</h3>
  <p>{{price}} руб.</p>
  <button>Изменить</button>
</div>

При клике на кнопку «Изменить» будет отправлен PUT-запрос на сервер, который обновит информацию о продукте. HTMX получит обновленные данные и заменит старое содержимое новым, не перезагружая страницу.

Заключение

Работа с коллекциями в HTMX предоставляет богатые возможности для динамичного взаимодействия с пользователем без необходимости перезагружать страницу. Циклы, пагинация, добавление и удаление элементов — все эти операции можно эффективно реализовать с помощью простых атрибутов и небольшого количества кода. Такой подход позволяет создавать быстрые и отзывчивые интерфейсы, которые идеально подходят для современных веб-приложений.