Ответ 1
Я бы предложил пометить строки, содержащие продукты с именем класса, например. "продукт", например:
<tr class="product {% cycle 'pure-table-odd', '' %}">
<td>
<img src="{{ product.featured_image.src | product_img_url: 'thumb' }}"
alt="{{ product.featured_image.alt | escape }}" />
</td>
<td>{{ product.title }}</td>
<td style="text-align:right">
<button type="button" name="click_me">Click Me</button>
</td>
</tr>
Вы не добавили бы этот класс к строкам, у которых есть варианты.
Затем в вашем JavaScript используйте метод nextUntil
для соответствия всем следующим рядам вариантов (которые не имеют класса "product" ) до тех пор, пока, но исключая следующую строку продукта и применяя метод toggle()
ко всем этим:
$("td button").click(function(){
$(this).closest('tr').nextUntil('.product').toggle();
});
Альтернативная структура 1
Вместо одной таблицы вы можете создавать вложенные таблицы, по одному для каждого продукта, содержащие варианты. Это выглядит примерно так:
<table class="pure-table pure-table-bordered">
<tbody>
{% for product in collection.products %}
{% if product.available %}
<tr class="{% cycle 'pure-table-odd', '' %}">
<td>
<img src="{{ product.featured_image.src | product_img_url: 'thumb' }}"
alt="{{ product.featured_image.alt | escape }}" />
</td>
<td>{{ product.title }}</td>
<td style="text-align:right">
<button type="button" name="click_me">Click Me</button>
</td>
</tr>
<tr>
<table class="some other class specific for variants">
<tbody>
{% for variant in product.variants %}
<tr>
<td>{{variant.title}}</td>
<td>{{variant.price | money }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</tr>
{% endif %}
{% endfor %}
</tbody>
</table>
У этого есть преимущества и недостатки. Основным недостатком является то, что столбцы этих подтабликов не выравниваются с столбцами в основной таблице. Но это зависит от того, что вы хотите...
Код JavaScript тогда должен был бы быть таким, каким он был изначально:
$("td button").click(function(){
$(this).closest('tr').next().toggle();
});
Альтернативная структура 2
Вы также можете обернуть каждую "секцию" (состоящую из одной строки продукта и строк вариантов, принадлежащих ей) тегом tbody
. Хотя это обычно не делается, это разрешено, как указано в MDN:
Обратите внимание, что в отличие от элементов
<thead>
,<tfoot>
и<caption>
, однако допускается несколько элементов<tbody>
(если они последовательны), позволяя разделять строки данных в длинных таблицах на разные разделы, каждый отдельно отформатированный по мере необходимости.
Это отличается от вашего исходного HTML, где у вас были tbody
элементы как дочерние элементы tr
, что является недопустимым HTML.
Это будет выглядеть так:
<table class="pure-table pure-table-bordered">
{% for product in collection.products %}
{% if product.available %}
<tbody>
<tr class="{% cycle 'pure-table-odd', '' %}">
<td>
<img src="{{ product.featured_image.src | product_img_url: 'thumb' }}"
alt="{{ product.featured_image.alt | escape }}" />
</td>
<td>{{ product.title }}</td>
<td style="text-align:right">
<button type="button" name="click_me">Click Me</button>
</td>
</tr>
{% for variant in product.variants %}
<tr>
<td>{{variant.title}}</td>
<td>{{variant.price | money }}</td>
</tr>
{% endfor %}
</tbody>
{% endif %}
{% endfor %}
</table>
Затем вы можете использовать метод nextAll()
, чтобы скрыть строки вариантов, поскольку они ограничены оболочкой tbody
из следующей строки продукта:
$("td button").click(function(){
$(this).closest('tr').nextAll().toggle();
});
Первоначально скрытие строк варианта
Если вы хотите, чтобы все варианты были сначала спрятаны, добавьте следующий атрибут к этим строкам в HTML-коде:
<tr style="display:hidden">
Вы бы, конечно, не делали этого для строк продукта. Кроме того, вы можете определить для этого класс CSS (например, tr.hidden { display:hidden; }
вместо style
).
Метод jQuery toggle()
будет переопределять этот style
при отображении и снова восстановить его при скрытии.