Товар

  1. Назначение атрибутов
  2. Селектор модификаций
  3. Методы класса Products
  4. События

Назначение атрибутов

Пример разметки товара

><form action="{{ cart_url }}" method="post" data-product-id="{{ product.id }}">
  <div class="product__sku">
    <span data-product-card-sku='{
        "skuLabel": "Артикул."
      }'
    ></span>
  </div>

  <span data-product-card-available='{
      "availableText": "Товар в наличии",
      "notAvailableText": "Нет в наличии"
    }'
  >
  </span>

  <div data-product-card-old-price></div>
  <div data-product-card-price></div>

  {% if product.show_variants? %}
    <select name="variant_id" data-product-variants='{"default": "option-radio"}'>
      {% for variant in product.variants %}
        <option value="{{ variant.id }}">{{ variant.title | escape }}</option>
      {% endfor %}
    </select>
  {% else %}
    <input type="hidden" name="variant_id" value="{{product.variants.first.id}}" >
  {% endif %}

  <input type="text" name="comment" value="">

  <div data-quantity data-min="1">
    <input type="text" name="quantity" value="1" />
    <span data-quantity-change="-1">-</span>
    <span data-quantity-change="1">+</span>
  </div>

  <button type="submit" data-item-add>
    Добавить в корзину
  </button>

  {% if account.quick_checkout.enabled %}
    <button data-quick-checkout="[data-product-id='{{ product.id }}']">
      Купить в 1 клик
    </button>
  {% endif %}
</form>

Атрибуты корневого элемента

data-product-id

Обязательный атрибут для инициализации товара, принимает ID товара:

<form data-product-id="{{ product.id }}" action="{{ cart_url }}" method="post">
  <!-- Код формы -->
</form>

data-product-without-cache

Отключение кэширования информации о товаре:

<form data-product-without-cache data-product-id="{{ product.id }}" action="{{ cart_url }}" method="post" >
  <!-- Код формы -->
</form>

data-product-json

Позволяет передать данные о товаре через Liquid. Это может ускорить отображение селектора вариантов.

<form data-product-id="{{ product.id }}" data-product-json="{{ product|json|escape }}" action="{{ cart_url }}" method="post">
  <!-- Код формы -->
</form>

data-set-config

Переча настроек товара через data-атрибут:

<form data-set-config='{"decimal": {"kgm": 1}}' data-product-id="{{ product.id }}" action="{{ cart_url }}" method="post">
  <!-- Код формы -->
</form>

Атрибуты вложенных элементов

data-product-variants

Каждый вариант товара состоит из свойств и их значений, например: "Цвет: Красный, Размер: 42", "Цвет: Синий, Размер: 38".

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

Доступные виды:

  • option-select
  • option-select-image
  • option-span
  • option-radio
  • option-preview
  • option-preview-text
  • option-default (option-select)

Разметка каждого вида хранится внутри библиотеки в виде lodash-шаблонов.

В следующем примере в качестве вида по умолчанию установлен option-select: для свойства "Цвет" - option-preview, для свойства "Размер" - option-span.

  {% if product.show_variants? %}
    <select name="variant_id" data-product-variants='{
      "default": "option-select",
      "Цвет": "option-preview",
      "Размер": "option-span"
    }'>
      {% for variant in product.variants %}
        <option value="{{ variant.id }}">{{ variant.title | escape }}</option>
      {% endfor %}
    </select>
  {% else %}
    <input type="hidden" name="variant_id" value="{{product.variants.first.id}}" >
  {% endif %}

Можно ли написать свой шаблон для отображения свойств?

Можно. Для этого в разметку нужно добавить тег script с data-атрибутом data-template-id, в качестве значения которого должен быть указан ID шаблона.

<script type="text/template" data-template-id="custom-span">
  <div class="<%= classes.option %> is-span">
    <label class="<%= classes.label %>"><%= title %></label>
    <div class="<%= classes.values %>">
      <% _.forEach(values, function (value){ %>
        <button class="<%= value.classes.all %> is-span"
          <%= value.controls %>
          <%= value.state %>
        >
          <%= value.title %>
        </button>
      <% }) %>
    </div>
  </div>
</script>

После чего можно указать свой шаблон по умолчанию.

  {% if product.show_variants? %}
    <select name="variant_id" data-product-variants='{
      "default": "custom-span"
    }'>
      {% for variant in product.variants %}
        <option value="{{ variant.id }}">{{ variant.title | escape }}</option>
      {% endfor %}
    </select>
  {% else %}
    <input type="hidden" name="variant_id" value="{{product.variants.first.id}}" >
  {% endif %}

data-quantity

Обязательный атрибут для обёртки кнопок изменения количества и инпута quantity

Для установки минимального значения в input количества товара передайте атрибут data-min с нужным значением

<div data-quantity>
  <button type="button" data-quantity-change="-1">-</button>
  <input type="text" value="1" name="quantity"/>
  <button type="button" data-quantity-change="1">+</button>
</div>

data-quantity-change

Атрибут для кнопок изменения количества +/-, принимает число

data-item-add

Добавление товара в корзину

data-add-cart-counter

Компонент, который совмещает в себе функционал добавления товара в корзину, изменения количества, отображения счётчика и возможность удаления из корзины. Он используется в виджетах карточек товаров в шаблонах 4 поколения.

В значении атрибута нужно указать шаг изменения количества товара: data-add-cart-counter='{"step": "1"}'

Вложенные элементы:

  • data-add-cart-counter-btn — кнопка добавления товара в корзину
  • data-add-cart-counter-minus — кнопка уменьшения количества или удаления из корзины
  • data-add-cart-counter-count — счётчик количества товара в корзине
  • data-add-cart-counter-plus — кнопка увеличения количества

События:

unchange_quantity:insales:ui_add-cart-counter — срабатывает, если достигнуто максимальное количество товара в корзине

EventBus.subscribe('unchange_quantity:insales:ui_add-cart-counter', data => {
  console.log(data);
})

Пример кода:

Всё что вам необходимо сделать для использования — это задать стили для элементов и скрывать/показывать нужные кнопки, если у корневого элемента есть класс is-add-cart.

<div class="add-cart-counter" data-add-cart-counter='{"step": "1"}'>
  <button type="button" class="add-cart-counter__btn" data-add-cart-counter-btn>
    Add to cart
  </button>
  <div class="add-cart-counter__controls">
    <button data-add-cart-counter-minus class="add-cart-counter__controls-btn" type="button">-</button>
    <a href="{{cart_url}}" class="add-cart-counter__detail">
      <span class="add-cart-counter__detail-text">{{messages.btn_buy_active_text}} <span data-add-cart-counter-count></span> {{ product.unit }}</span>
    </a>
    <button data-add-cart-counter-plus class="add-cart-counter__controls-btn" type="button">+</button>
  </div>
</div>

data-product-card-preorder

Атрибут предназначен для кнопки вызова формы предзаказа. При загрузке страницы кнопка получает атрибуты data-preorder-product-name и data-preorder-variant, которые содержат название товара и название выбранного варианта.

Значение атрибута data-preorder-variant обновляется при выборе варианта товара.

Если подписаться на EventBus-событие show-preorder:insales:ui_product, то при нажатии на кнопку вы сможете получать название товара и выбранного варианта, чтобы использовать их в форме предзаказа.

<button data-product-card-preorder type="button">{{messages.pre_order}}</button>

data-quick-checkout

Форма заказа в один клик

<button data-quick-checkout></button>

В качестве значения можно передать ID конкретного товара. Однако, если в корзину уже добавлены другие товары, то они тоже попадут в заказ.

<button data-quick-checkout="[data-product-id='{{ product.id }}']"></button>

data-product-card-price

Цена продажи варианта товара

<span data-product-card-price></span>

data-product-card-price-from-cart

Цена продажи варианта товара с учётом типов цен

<span data-product-card-price-from-cart></span>

data-product-card-old-price

Старая цена варианта товара

<span data-product-card-old-price></span>

data-product-card-sku

Получение артикула варианта товара. В качестве значения можно передать label.

<span data-product-card-sku='{"skuLabel": "{{messages.sku_label}}"}'></span>

data-product-card-available

Наличие варианта товара.

В качестве значения можно передать объект со статусами.

<span data-product-card-available='{"availableText": "Available", "notAvailableText": "Not available"}'>

name="comment"

Комментарий к позиции заказа. Для корректной работы необходимо, чтобы комментарии к заказам были включены в админ-панели, в разделе "Настройки" > "Оформление заказа"

<input type="text" name="comment" value="">

Селектор модификаций

Привязка шаблона модификации к опции

В методе setConfig нужно передать объект options в виде имя опции: ID шаблона

Products.setConfig({
  options: {
    'Цвет': 'option-image',
    'Размер': 'option-radio',
    'Материал': 'option-select',
    'Жесткий диск': 'option-span'
  }
});

Пример шаблона

<script type="text/template" data-template-id="option-span">
  <div class="<%= classes.option %> is-span">
    <label class="<%= classes.label %>"><%= title %></label>
    <div class="<%= classes.values %>">
      <% _.forEach(values, function (value){ %>
        <button class="<%= value.classes.all %> is-span"
          <%= value.controls %>
          <%= value.state %>
        >
          <%= value.title %>
        </button>
      <% }) %>
    </div>
  </div>
</script>

Передать изображения для шаблона селектора модификаций

Ссылки формируются в виде значение свойства + .png | file_url

<script>
  {% comment %}
    создание объекта с картинками из файлов для collection
  {% endcomment %}
  if (!fileUrl) {
   var fileUrl = {}
  }
  {% assign option_title  = 'Цвет' %}
  {% assign collection_handle  = 'all' %}
  {% assign image_format  = '.png' %}
  {% for option_name in collections[collection_handle].options %}
    {% if option_name.title == option_title %}
      {% for option_value in option_name.values %}
        {% capture fileName %}{{option_value.title | replace: ' ',  '_' }}{{image_format}}{% endcapture %}
        {% assign fileURL = fileName | file_url  %}
        {% if fileURL %}
          fileUrl['{{ option_value.title | downcase }}'] = '{{ fileURL }}';
        {% endif %}
      {% endfor %}
    {% endif %}
  {% endfor %}
</script>

<script>
  {% comment %}
    создание объекта с картинками из файлов для product
  {% endcomment %}
  if (!fileUrl) {
   var fileUrl = {}
  }
  {% assign option_title  = 'цвет' %}
  {% assign image_format  = '.png' %}
  {% for option in product.options %}
    {% assign option-title = option.title | downcase %}
    {% if option-title == option_title %}
     {% for value in option.values %}
       {% capture fileName %}{{value.title | replace: ' ',  '_'}}{{image_format}}{% endcapture %}
       {% assign fileURL = fileName | downcase | file_url  %}
       {% if fileURL %}
        fileUrl['{{ value.title | downcase }}'] = encodeURI('{{ fileURL }}');
       {% endif %}
     {% endfor %}
    {% endif %}
  {% endfor %}
</script>

<script>
  Products.setConfig({
    fileUrl: (typeof fileUrl == 'undefined') ? {} : fileUrl
  });
</script>

Шаблоны для селектора модификаций

select

<script type="text/template" data-template-id="option-select">
  <div class="<%= classes.option %> is-select">
    <label class="<%= classes.label %>"><%= title %></label>
    <select class="<%= classes.values %>" data-option-bind="<%= option.id %>">
      <% _.forEach(values, function (value){ %>
        <option
          <%= value.controls %>
          <%= value.state %>
        >
          <%= value.title %>
        </option>
      <% }) %>
    </select>
  </div>
</script>

select-image

<script type="text/template" data-template-id="option-select-image">
<div class="<%= classes.option %> <%= _.find(values, 'image_url') ? 'is-system-color' : '' %> is-select">
  <% if (_.find(values, 'image_url')) { %>
    <label class="<%= classes.label %>">
      <%= title %>
    </label>
    <div class="<%= classes.values %>">
      <% _.forEach(values, function (value){ %>
        <label class="<%= value.classes.all %> is-radio">
          <input class="<%= value.classes.state %>" type="radio" name="<%= handle %>" <%= value.state %>
          <%= value.controls %>
            >
            <span class="option-value-system-color <%= value.image_url ? 'with-image-color' : 'without-image-color' %>">
              <% if (value.image_url) { %>
                <img width="40px" src="<%= value.image_url %>" alt="<%= value.titleWithoutQuotes %>"
                  title="<%= value.titleWithoutQuotes %>">
                <% } else { %>
                  <%= value.title %>
                <% } %>
            </span>
        </label>
        <% }) %>
    </div>
  <% } else { %>
    <label class="<%= classes.label %>"><%= title %></label>
      <select class="<%= classes.values %>" data-option-bind="<%= option.id %>">
        <% _.forEach(values, function (value){ %>
          <option
            <%= value.controls %>
            <%= value.state %>
          >
            <%= value.title %>
          </option>
        <% }) %>
      </select>
    <% } %>
</div>
</script>

span

<script type="text/template" data-template-id="option-span">
  <div class="<%= classes.option %> is-span">
    <label class="<%= classes.label %>"><%= title %></label>
    <div class="<%= classes.values %>">
      <% _.forEach(values, function (value){ %>
        <button class="<%= value.classes.all %> is-span"
          <%= value.controls %>
          <%= value.state %>
        >
          <%= value.title %>
        </button>
      <% }) %>
    </div>
  </div>
</script>

radio

<script type="text/template" data-template-id="option-radio">
  <div class="<%= classes.option %> is-radio">
    <label class="<%= classes.label %>"><%= title %></label>
    <div class="<%= classes.values %>">
      <% _.forEach(values, function (value){ %>
        <label class="<%= value.classes.all %> is-radio">
          <input class="<%= value.classes.state %>"
            type="radio"
            name="<%= handle %>"
            <%= value.state %>
            <%= value.controls %>
          >
          <span><%= value.title %></span>
        </label>
      <% }) %>
    </div>
  </div>
</script>

preview

<script type="text/template" data-template-id="option-preview">
<div class="<%= classes.option %> option-<%= option.handle %>" is-span is-preview">
  <label class="<%= classes.label %>"><%= title %></label>
  <div class="<%= classes.values %>">
    <% _.forEach(values, function (value){ %>
      <button class="<%= value.classes.all %> is-span is-preview"
        <%= value.controls %>
        <%= value.state %>
      >
        <% if(value.imageFromVariant){ %>
          <img width="40px" src="<%= value.imageFromVariant.medium_url %>" alt="<%= value.titleWithoutQuotes %>" title="<%= value.titleWithoutQuotes %>">
        <% }else{ %>
          <span><%= value.title %></span>
        <% } %>
      </button>
    <% }) %>
  </div>
</div>
</script>

preview-text

<script type="text/template" data-template-id="option-preview-text">
<div class="<%= classes.option %> is-span is-preview-text">
  <label class="<%= classes.label %>">
    <%= title %>
  </label>
  <div class="<%= classes.values %>">
    <% _.forEach(values, function (value){ %>
      <button class="<%= value.classes.all %> is-span is-preview-text <%= (value.variant.image_id ? 'is-img' : 'is-text') %>" <%= value.controls %>
        <%= value.state %>
          >
            <% if(value.imageFromVariant && value.variant.image_id){ %>
              <img width="40px" src="<%= value.imageFromVariant.medium_url %>" alt="<%= value.titleWithoutQuotes %>"
                title="<%= value.titleWithoutQuotes %>">
            <% }else{ %>
              <span>
                <%= value.title %>
              </span>
              <% } %>
      </button>
      <% }) %>
  </div>
</div>
</script>

Методы класса Products

get

Получить объект с информацией о конкретном товаре

/**
 * @param {number} id id товара
 * @return {Deferred}
 */
Products.get(123456)
  .done(function (onDone) { console.log('onDone', onDone) })
  .fail(function (onFail) { console.log('onFail', onFail) });

getList

Получение списка товаров

/**
 * @param {Array} idList - массив, состоящий из id товаров
 * @param {Object} options - объект, в котором можно передать опцию no_cache, если необходимо не кешировать товары в local storage.
 * @return {Deferred}
 */
Products.getList([123456, 123455, 1234454, 123458])
  .done(function (onDone) { console.log('onDone', onDone) })
  .fail(function (onFail) { console.log('onFail', onFail) });

Важно: все полученные товары кэшируются в local storage. Это означает, что при отправке новых запросов товары, которые уже были получены с сервера в предыдущих запросах, будут доставаться из кэша. Это работает только в рамках одной сессии. То есть, если перезагрузить страницу, то товары снова будут получены запросом. Если по каким-то причинам вам нужно, чтобы этого не происходило, то необходимо вторым аргументом передать объект со свойством no_cache и значением true.

В одном запросе можно получить не более 700 товаров. Если превысить этот лимит, то перед отправкой запроса на сервер массив будет обрезан.

setConfig

Обновление настроек - Параметры

Property
Default
Назначение
options
{ 'default': 'option-default' }
Через данный объект задаются шаблоны для вывода свойств варианта
fileUrl
Пустой объект
Объект для хранения картинок из раздела «Файлы»
decimal
Пустой объект
Количество символов после запятой для единиц измерения
filtered
true
Если значение true, то недоступные опции не выводятся в шаблон.
disableHideItem
false
Показывает отсутствующие в наличии варианты товаров, даже если в админ-панели их отображение отключено
selectUnavailable
true
Разрешить выбирать недоступный вариант (актуально если filtered: false)
allowUnavailable
false
Разрешить выбирать первым недоступный вариант
showVariants
true
При значении false рендер вариантов не производится
initOption
true
Отмечать активные свойства при инициализации?
useMax
false
Использовать максимальное количество? Если значение true, в quantity невозможно указать количество больше, чем доступно на складе

Важно: вызов данного метода стоит оставлять в глобальной области видимости. Если запустить метод внутри $(document).ready(function() {}), результат может быть непредсказуем.

Products.setConfig({
  showVariants: true,
  hideSelect: true,
  initOption: true,
  fileUrl: (typeof fileUrl == 'undefined') ? {} : fileUrl,
  filtered: true,
  selectUnavailable: true
})

getInstance

Получаем экземпляр класса ProductInstance из jQuery DOM element

/**
 * @param {jQuery DOM element} $node jQuery DOM element например $('.product-cart-control')
 */
 Products.getInstance($('.product-cart-control'))
   .done(function (onDone) { console.log('onDone', onDone) })
   .fail(function (onFail) { console.log('onFail', onFail) });

initInstance

Инициализация формы товара

/**
 * @param {jQuery DOM element} $node jQuery DOM element например $('.product-cart-control')
 */
Products.initInstance($('.product-cart-control'))
   .done(function (onDone) { console.log('onDone', onDone) })
   .fail(function (onFail) { console.log('onFail', onFail) });

getRecentlyViewed

Возвращает массив с ID просмотренных товаров

Products.getRecentlyViewed()
   .done(function (onDone) { console.log('onDone', onDone) })
   .fail(function (onFail) { console.log('onFail', onFail) });

События

Событие
Описание
init_instance:insales:product
Срабатывает после инициализации оберток [data-product-id] с инициализацией всех дочерних элементов
before:insales:product
Срабатывает перед любым взаимодействием с компонентом товара
always:insales:product
Срабатывает после любого взаимодействия с компонентом товара
change_quantity:insales:product
Обновление количества товара в инпуте quantity
unchange_quantity:insales:product
Если введено количество больше доступного
overload:quantity:insales:product
Событие срабатывает, когда с помощью +/- накликали до максимального значения quantity (Работает, если вы используете параметр useMax)
max:quantity:insales:product
Срабатывает всегда, когда в инпуте установлено максимальное кол-во, даже при загрузке страницы (Работает, если вы используете параметр useMax)
change_variant:insales:product
Срабатывает при выборе варианта товара
update_variant:insales:product
Обновление варианта товара

Пример подписки на событие

EventBus.subscribe('change_quantity:insales:product', function (data) {
  console.log('Изменено количество товара в счётчике', data);
}); 

Оставить оценку

Оценка успешно отправлена.
Она будет проверена администратором перед публикацией.
Перед публикацией все оценки проходят модерацию

Оценки: 2

Комментарий
Добрый день! Пробую ваш код из примера для использования собственного lodash шаблона для отображения вариантов, получаю ошибку: - Ошибка рендера шаблона: my-product-variant-232. Проверьте корректность шаблона - TypeError: _.forEach is not a function Точно ли подключен lodash и доступны все его возможности в шаблонах?
Ответ разработчика:
Добрый день!
Напишите, пожалуйста, обращение в техническую поддержку. Специалисты смогут посмотреть код шаблона и проверить, в чём причина ошибки.
Комментарий
Добрый день. Возможно ли как-либо вывести количество остатков товара в карточку?
Ответ разработчика:
Добрый день!
Да, остатки вариантов товара хранятся в переменной variant.quantity, все варианты товара хранятся в переменной product.variants. Подробнее о работе с переменными можно прочитать в инструкции
Для изменения кода карточки товара нужно в редакторе шаблона зайти в виджет карточки товара и во вкладке "Дизайн" нажать "Изменить код".
Если возникнут трудности, можно обратиться в техническую поддержку, специалисты помогут добавить вывод остатков в карточку.
Остались вопросы?
Отправь тикет в техподдержку!
Еще нет своего магазина?
Создайте интернет-магазин на платформе inSales
Всё для продаж уже внутри!
Нажимая кнопку «Зарегистрироваться», я принимаю Пользовательское соглашение и Политику конфиденциальности
Недавно просмотренные статьи
Продолжая пользоваться сайтом,
вы соглашаетесь с использованием cookie