Skip to content

Instantly share code, notes, and snippets.

@suhag10
Created May 1, 2026 17:18
Show Gist options
  • Select an option

  • Save suhag10/f16b0d7c80e60aa968b8e333af49e8c0 to your computer and use it in GitHub Desktop.

Select an option

Save suhag10/f16b0d7c80e60aa968b8e333af49e8c0 to your computer and use it in GitHub Desktop.

Handle quantity increments and decrements

Modularized code into reusable functions.

jQuery(function ($) {
    /**
     * Utility: Get decimal places of a number string
     */
    if (!String.prototype.getDecimals) {
        String.prototype.getDecimals = function () {
            const match = String(this).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
            if (!match) return 0;

            const decimals = match[1] ? match[1].length : 0;
            const exponent = match[2] ? parseInt(match[2], 10) : 0;

            return Math.max(0, decimals - exponent);
        };
    }

    /**
     * Reusable function to update quantity value
     * @param {jQuery} $input - jQuery object of the input element
     * @param {boolean} increment - true to increment, false to decrement
     */
    function updateQuantity($input, increment) {
        let currentVal = parseFloat($input.val()) || 0;
        let max = parseFloat($input.attr('max'));
        let min = parseFloat($input.attr('min')) || 0;
        let stepAttr = $input.attr('step');
        let step = (stepAttr === 'any' || !stepAttr || isNaN(parseFloat(stepAttr))) ? 1 : parseFloat(stepAttr);

        if (increment) {
            if (!isNaN(max) && currentVal >= max) {
                $input.val(max);
            } else {
                $input.val((currentVal + step).toFixed(String(step).getDecimals()));
                $input.val(currentVal + step).attr("value", (currentVal + step));
            }
        } else {
            if (!isNaN(min) && currentVal <= min) {
                $input.val(min);
            } else if (currentVal > 0) {
                $input.val((currentVal - step).toFixed(String(step).getDecimals()));
                $input.val(currentVal - step).attr("value", (currentVal - step));
            }
        }

        $input.trigger('change');
    }

    /**
     * Handle quantity increment/decrement
     */
    $(document.body).on('click', '.cart-plus, .cart-minus', function () {
        const $qty = $(this).closest('.product-quantity').find('.cart-input');
        updateQuantity($qty, $(this).hasClass('cart-plus'));
    });

    $('.cart-input').on('keydown', function (e) {
        const $qty = $(this);
        if (e.key === "ArrowUp") {
            updateQuantity($qty, true);
        }
        if (e.key === "ArrowDown") {
            updateQuantity($qty, false);
        }
    });
});

Emphasized readability and maintainability.

jQuery(function ($) {
    // Utility: Get decimal places of a number string
    if (!String.prototype.getDecimals) {
        String.prototype.getDecimals = function () {
            const match = String(this).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);
            if (!match) return 0;

            const decimals = match[1] ? match[1].length : 0;
            const exponent = match[2] ? parseInt(match[2], 10) : 0;

            return Math.max(0, decimals - exponent);
        };
    }

    // Handle quantity increment/decrement
    $(document.body).on('click', '.cart-plus, .cart-minus', function () {
        const $qty = $(this).closest('.product-quantity').find('.cart-input');

        let currentVal = parseFloat($qty.val()) || 0;
        let max = parseFloat($qty.attr('max'));
        let min = parseFloat($qty.attr('min')) || 0;
        let stepAttr = $qty.attr('step');
        let step = (stepAttr === 'any' || !stepAttr || isNaN(parseFloat(stepAttr))) ? 1 : parseFloat(stepAttr);

        // Increment or decrement
        if ($(this).hasClass('cart-plus')) {
            if (!isNaN(max) && currentVal >= max) {
                $qty.val(max);
            } else {
                $qty.val((currentVal + step).toFixed(String(step).getDecimals()));
                $qty.val(currentVal + step).attr("value", (currentVal + step));
            }
        } else {
            if (!isNaN(min) && currentVal <= min) {
                $qty.val(min);
            } else if (currentVal > 0) {
                $qty.val((currentVal - step).toFixed(String(step).getDecimals()));
                $qty.val(currentVal - step).attr("value", (currentVal - step));
            }
        }

        // Trigger change event
        $qty.trigger('change');
    });
});

Simplified complex logic into clean code.

$('.cart-minus').on('click', function () {
	var $input = $(this).parent().find('input');
	var count = parseInt($input.val()) - 1;
	count = count < 1 ? 1 : count;
	$input.val(count);
	$input.change();
	return false;
});

$('.cart-plus').on('click', function () {
	var $input = $(this).parent().find('input');
	var currentVal = parseInt($input.val()) || 0;
	var maxVal = $input.attr('max'); // Read the max attribute.

	if (maxVal) {
		// If the max attribute exists, it must be enforced.
		maxVal = parseInt(maxVal);
		if (currentVal < maxVal) {
			$input.val(currentVal + 1);
			$input.change();
		}
	} else {
		// If the max attribute is absent, allow unlimited increments.
		$input.val(currentVal + 1);
		$input.change();
	}

	return false;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment