Плюс и минус в каунте корзины MS2

Досточно простой вопрос, который мучает начинающих разработчиков. Решил поделиться решением, как сделать кнопки плюс и минус в корзине MS2. Что бы все было «по-фуншую»

Начнем c разметки. Я показываю на страндартной теме MS2. Вносим правки в чанк tpl.msCart

...
<td class="count">
<form method="post" class="ms2_form" role="form">
  <input type="hidden" name="key" value="{$product.key}"/>
  <div class="form-group">
    <div class="input-group input-group-sm qty">
      <span class="input-group-prepend">
      <span class="input-group-text minus input_count_action">-</span>
      </span>
      <input type="number" name="count" value="{$product.count}" class="form-control"/>
      <span class="input-group-append">
      <span class="input-group-text plus input_count_action">+</span>
      <span class="input-group-text">{'ms2_frontend_count_unit' | lexicon}</span>
      </span>
    </div>
      <button class="btn btn-sm" type="submit" name="ms2_action" value="cart/change">
      ↻</button>
  </div>
</form>
</td>
...


Далее подключим JS файл и подключим его последним.

{$_modx->regClientScript("assets/js/ms2.js")}

И далее напишем ms2.js

$(document).ready(function() {

  $('.qty').on('click', '.input_count_action', function(e) {

    var $input = $(this).closest("div").find('input');
    var count = parseInt($input.val());

    if ($(this).hasClass("plus")) {
      count = count + 1;
    } else if ($(this).hasClass("minus")) {
      count = count - 1;
    }
    
    $input.val(count);
    $input.change();
    return false;
  });

  $('div.count').click(function(e) {
    var v = $(this).parent().find('input#product_price').val(),
      k = $(this).parent().find('input[name="key"]').val();

    if (($(this).hasClass('minus') || $(this).hasClass('plus')) && v > 0) {

      $.post("", {
        ms2_action: 'cart/change',
        key: k,
        count: v
      }, function(response) {

        if (typeof response.success !== "undefined") {

          if (response.success) {
            miniShop2.Order.getcost();
            miniShop2.Cart.status(response.data);
          }
        }
      }, "json");

    }
  });

	miniShop2.Callbacks.Cart.change.before = function() {
		var $field = $(miniShop2.sendData.$form[0]).find(miniShop2.Cart.countInput);
		var count = +$field.val();
		if (count < 1) {
			$field.val('1');
			miniShop2.Message.error('Ошибка! Нельзя ставить кол-во меньше 1!');
			return false;
		}
		return true;
	}
});
И получаем результат.



Решение от @mngatoff

<script>
$(document)
    .on('click touchend', countButton, function (e) { // где countButton - кнопки плюс и минус
        e.preventDefault();
        var $container = $(this).closest('.ms2_form'),
        $count = $container.find('[name="count"]'),
        num = $count.val();
        if (isNaN(num) === false) { // страховочка от, например, пустого поля
            num = parseInt(num, 10);
            switch ($(this).data('ms2-count')) { // соответственно, у кнопок должен быть атрибут data-ms2-count="plus или minus"
                case 'plus':
                    num = num + 1;
                    $count.val(num);
                    break;
                case 'minus':
                    if (num <= 1) return;
                    num = num - 1;
                    $count.val(num);
                    break;
            }
        } else {
            return false;
        }
        $count.trigger('change'); // инициализируем отправку на сервер.
    })
    .on('change keypress keyup', '.ms2_form [name="count"]', function() {
        if ($(this).val().match(/\D/)) {
            this.value = $(this).val().replace(/\D/g,''); // следим на лету, чтобы в поле были только цифры
        }
        if (parseInt($(this).val(), 10) < 1) {
            this.value = 1; // следим на лету, чтобы в поле было не меньше единицы
        }
    });
</script>
Ну и обязательно ставим плюсы первому комментарию)
Олег Щавелев
02 декабря 2019, 02:08
modx.pro
3
206
+8

Комментарии: 9

mngatoff
02 декабря 2019, 02:23
3
+7
достаточно триггернуть событие change на input:count, и запрос отправится стандартными средствами минишопа.

я вот так делаю (немного вырвано из контекста, но принцип ясен):
<script>
$(document)
    .on('click touchend', countButton, function (e) { // где countButton - кнопки плюс и минус
        e.preventDefault();
        var $container = $(this).closest('.ms2_form'),
        $count = $container.find('[name="count"]'),
        num = $count.val();
        if (isNaN(num) === false) { // страховочка от, например, пустого поля
            num = parseInt(num, 10);
            switch ($(this).data('ms2-count')) { // соответственно, у кнопок должен быть атрибут data-ms2-count="plus или minus"
                case 'plus':
                    num = num + 1;
                    $count.val(num);
                    break;
                case 'minus':
                    if (num <= 1) return;
                    num = num - 1;
                    $count.val(num);
                    break;
            }
        } else {
            return false;
        }
        $count.trigger('change'); // инициализируем отправку на сервер.
    })
    .on('change keypress keyup', '.ms2_form [name="count"]', function() {
        if ($(this).val().match(/\D/)) {
            this.value = $(this).val().replace(/\D/g,''); // следим на лету, чтобы в поле были только цифры
        }
        if (parseInt($(this).val(), 10) < 1) {
            this.value = 1; // следим на лету, чтобы в поле было не меньше единицы
        }
    });
</script>
    mngatoff
    02 декабря 2019, 02:25
    0
    плюс этого варианта еще и в том, что его можно без изменений использовать в карточке товара в форме добавления в корзину
      Олег Щавелев
      03 декабря 2019, 10:32
      0
      Cпасибо за решение. Добавил как альтернативное в тело статьи.
    Баха Волков
    02 декабря 2019, 10:32
    +2
    Действительно, вот эта часть вашего кода:

    $('div.count').click(function(e) {
        var v = $(this).parent().find('input#product_price').val(),
          k = $(this).parent().find('input[name="key"]').val();
    
        if (($(this).hasClass('minus') || $(this).hasClass('plus')) && v > 0) {
    
          $.post("", {
            ms2_action: 'cart/change',
            key: k,
            count: v
          }, function(response) {
    
            if (typeof response.success !== "undefined") {
    
              if (response.success) {
                miniShop2.Order.getcost();
                miniShop2.Cart.status(response.data);
              }
            }
          }, "json");
    
        }
      });

    ну очень не нужна

    Обратите внимание, что на изменение input[name=count] повешена функция которая отправляет форму.

    @mngatoff как раз и предлагает воспользоваться методом trigger или на худой конец можно было бы самостоятельно сабмитить форму
      Баха Волков
      02 декабря 2019, 10:46
      +3
      И еще позвольте немного покритиковать, сюдя по этой вашей строчке:

      var v = $(this).parent().find('input#product_price').val(),

      у каждого товара в корзине есть input с id=«product_price»… Транслируя готовые решения или пошаговые инструкции по хорошему нужно осознавать некую ответственность.

      Идентификатор в коде документа должен быть в единственном экземпляре
    Павел Гвоздь
    03 декабря 2019, 08:40
    0
    Соглашусь с комментариями выше и прошу исправить решение в посте в соответствии с ними! Ибо потом производятся сайты, созданные на копипасте (без мозгов), которые приходится корректировать мне или другим адекватным разработчикам.

    Ну и хорошо бы вставлять код в пост не как попало, а хоть как-то его корректируя. Зачем в первом блоке с HTML кодом эти табы вначале каждой строки?
      Олег Щавелев
      03 декабря 2019, 10:43
      0
      Ну и хорошо бы вставлять код в пост не как попало, а хоть как-то его корректируя. 
      Зачем в первом блоке с HTML кодом эти табы вначале каждой строки?
      Каюсь) Поправил.
        Олег Щавелев
        03 декабря 2019, 10:45
        0
        Соглашусь с комментариями выше и прошу исправить решение в посте в соответствии с ними!
        Обязательно вникну и поправлю основываясь на комментариях выше.
        Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
        9