Have your say in Community Polls: What was/is your greatest motivation to start your own business?
Our Partner & Developer boards on the community are moving to a brand new home: the .dev community forums! While you can still access past discussions here, for all your future app and storefront building questions, head over to the new forums.

Cart Ajax API is always showing Sold out when adding a new variant

Solved

Cart Ajax API is always showing Sold out when adding a new variant

jam_chan
Shopify Partner
927 23 190

I am developing an app to create product bundles. Firstly, I help customers to create a new variant with the quantity equals to 1 after selection. After that, I am using Cart ajax API to add this new variant to Cart. However, when I add the new variant with Fetch API, it's always showing sold out

{status: 422, message: "Cart Error", description: "The product xxxx is already sold out."}

Here is the code to add the new variant to Cart (I copied from doc):

addNewVariantToCart(variant_id) {
        let formData = {
           'items': [{
            'id': parseInt(variant_id),
            'quantity': 1
            }]
          };
		
        fetch('/cart/add.js', {
          method: 'POST',
          headers: {
            //               'Accept': 'application/json',
            'Content-Type': 'application/json'
          },
          body: JSON.stringify(formData)
        })
        .then(response => response.json())
        .then(data => {
          console.log('Success adding variant to cart:', data);
          //             console.log('Your bundle has been added to cart! Check your cart now.')
        })
        .catch((error) => {
          console.error('Error:', error);
        });
      }

When I run these code in Chrome console by substituting the new variant id, it works without any problem. What's wrong here?

BYOB - Build Your Own Bundles, SPO - SEO App to research keywords & edit social link preview
Accepted Solution (1)

jam_chan
Shopify Partner
927 23 190

This is an accepted solution.

I found the solution in another thread. Just set 'inventory_policy' to 'continue' and it'll be fine. 

BYOB - Build Your Own Bundles, SPO - SEO App to research keywords & edit social link preview

View solution in original post

Replies 2 (2)

MikeBee
Tourist
7 1 2

Hi,

I have the same error message when trying to add to cart a product out of stock; I tried everything to get a pop message that this product is out of stock instead of this alert but it didn't work!!

 

errorFashe.jpg

 

 

This is below my Ajaxify.js.liquid:

 

Click to expand...

/*============================================================================
(c) Copyright 2015 Shopify Inc. Author: Carson Shold (@cshold). All Rights Reserved.

Plugin Documentation - https://shopify.github.io/Timber/#ajax-cart

Ajaxify the add to cart experience and flip the button for inline confirmation,
show the cart in a modal, or a 3D drawer.

This file includes:
- Basic Shopify Ajax API calls
- Ajaxify plugin

This requires:
- jQuery 1.8+
- handlebars.min.js (for cart template)
- modernizer.min.js
- snippet/ajax-cart-template.liquid

JQUERY API (c) Copyright 2009-2015 Shopify Inc. Author: Caroline Schnapp. All Rights Reserved.
Includes slight modifications to addItemFromForm.
==============================================================================*/
if ((typeof Shopify) === 'undefined') { Shopify = {}; }

/*============================================================================
API Helper Functions
==============================================================================*/
function attributeToString(attribute) {
if ((typeof attribute) !== 'string') {
attribute += '';
if (attribute === 'undefined') {
attribute = '';
}
}
return jQuery.trim(attribute);
}

/*============================================================================
API Functions
- Shopify.format money is defined in option_selection.js.
If that file is not included, it is redefined here.
==============================================================================*/
if ( !Shopify.formatMoney ) {
Shopify.formatMoney = function(cents, format) {
var value = '',
placeholderRegex = /\{\{\s*(\w+)\s*\}\}/,
formatString = (format || this.money_format);

if (typeof cents == 'string') {
cents = cents.replace('.','');
}

function defaultOption(opt, def) {
return (typeof opt == 'undefined' ? def : opt);
}

function formatWithDelimiters(number, precision, thousands, decimal) {
precision = defaultOption(precision, 2);
thousands = defaultOption(thousands, ',');
decimal = defaultOption(decimal, '.');

if (isNaN(number) || number == null) {
return 0;
}

number = (number/100.0).toFixed(precision);

var parts = number.split('.'),
dollars = parts[0].replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1' + thousands),
cents = parts[1] ? (decimal + parts[1]) : '';

return dollars + cents;
}

switch(formatString.match(placeholderRegex)[1]) {
case 'amount':
value = formatWithDelimiters(cents, 2);
break;
case 'amount_no_decimals':
value = formatWithDelimiters(cents, 0);
break;
case 'amount_with_comma_separator':
value = formatWithDelimiters(cents, 2, '.', ',');
break;
case 'amount_no_decimals_with_comma_separator':
value = formatWithDelimiters(cents, 0, '.', ',');
break;
}

return formatString.replace(placeholderRegex, value);
};
}

Shopify.onProduct = function(product) {
// alert('Received everything we ever wanted to know about ' + product.title);
};

Shopify.onCartUpdate = function(cart) {
// alert('There are now ' + cart.item_count + ' items in the cart.');
};

Shopify.updateCartNote = function(note, callback) {
var params = {
type: 'POST',
url: '/cart/update.js',
data: 'note=' + attributeToString(note),
dataType: 'json',
success: function(cart) {
if ((typeof callback) === 'function') {
callback(cart);
}
else {
Shopify.onCartUpdate(cart);
}
},
error: function(XMLHttpRequest, textStatus) {
Shopify.onError(XMLHttpRequest, textStatus);
}
};
jQuery.ajax(params);
};

Shopify.onError = function(XMLHttpRequest, textStatus) {
var data = eval('(' + XMLHttpRequest.responseText + ')');
if (!!data.message) {
alert(data.message + '(' + data.status + '): ' + data.description);
} else {
alert('Error : ' + Shopify.fullMessagesFromErrors(data).join('; ') + '.');
}
};

/*============================================================================
POST to cart/add.js returns the JSON of the line item associated with the added item
==============================================================================*/
Shopify.addItem = function(variant_id, quantity, callback) {
var quantity = quantity || 1;
var params = {
type: 'POST',
url: '/cart/add.js',
data: 'quantity=' + quantity + '&id=' + variant_id,
dataType: 'json',
success: function(line_item) {
if ((typeof callback) === 'function') {
callback(line_item);
}
else {
Shopify.onItemAdded(line_item);
}
},
error: function(XMLHttpRequest, textStatus) {
Shopify.onError(XMLHttpRequest, textStatus);
}
};
jQuery.ajax(params);
};

/*============================================================================
POST to cart/add.js returns the JSON of the line item
- Allow use of form element instead of id
- Allow custom error callback
==============================================================================*/
Shopify.addItemFromForm = function(form, callback, errorCallback) {
var params = {
type: 'POST',
url: '/cart/add.js',
data: jQuery(form).serialize(),
dataType: 'json',
success: function(line_item) {
if ((typeof callback) === 'function') {
callback(line_item, form);
}
else {
Shopify.onItemAdded(line_item, form);
}
},
error: function(XMLHttpRequest, textStatus) {
if ((typeof errorCallback) === 'function') {
errorCallback(XMLHttpRequest, textStatus);
}
else {
Shopify.onError(XMLHttpRequest, textStatus);
}
}
};
jQuery.ajax(params);
};

// Get from cart.js returns the cart in JSON
Shopify.getCart = function(callback) {
jQuery.getJSON('/cart.js', function (cart, textStatus) {
if ((typeof callback) === 'function') {
callback(cart);
}
else {
Shopify.onCartUpdate(cart);
}
});
};

// GET products/<product-handle>.js returns the product in JSON
Shopify.getProduct = function(handle, callback) {
jQuery.getJSON('/products/' + handle + '.js', function (product, textStatus) {
if ((typeof callback) === 'function') {
callback(product);
}
else {
Shopify.onProduct(product);
}
});
};

// POST to cart/change.js returns the cart in JSON
Shopify.changeItem = function(line, quantity, callback) {
var params = {
type: 'POST',
url: '/cart/change.js',
data: 'quantity=' + quantity + '&line=' + line,
dataType: 'json',
success: function(cart) {
if ((typeof callback) === 'function') {
callback(cart);
}
else {
Shopify.onCartUpdate(cart);
}
},
error: function(XMLHttpRequest, textStatus) {
Shopify.onError(XMLHttpRequest, textStatus);
}
};
jQuery.ajax(params);
};

/*============================================================================
Ajaxify Shopify Add To Cart
==============================================================================*/
var ajaxifyShopify = (function(module, $) {

'use strict';

// Public functions
var init;

// Private general variables
var settings, isUpdating, cartInit, $drawerHeight, $cssTransforms, $cssTransforms3d, $nojQueryLoad, $w, $body, $html;

// Private plugin variables
var $formContainer, $btnClass, $wrapperClass, $addToCart, $flipClose, $flipCart, $flipContainer, $cartCountSelector, $cartCostSelector, $toggleCartButton, $modal, $cartContainer, $drawerCaret, $modalContainer, $modalOverlay, $closeCart, $drawerContainer, $prependDrawerTo, $callbackData={};

// Private functions
var updateCountPrice, flipSetup, revertFlipButton, modalSetup, showModal, sizeModal, hideModal, drawerSetup, showDrawer, hideDrawer, sizeDrawer, loadCartImages, formOverride, itemAddedCallback, itemErrorCallback, cartUpdateCallback, setToggleButtons, flipCartUpdateCallback, buildCart, cartTemplate, adjustCart, adjustCartCallback, createQtySelectors, qtySelectors, scrollTop, toggleCallback, validateQty;

/*============================================================================
Initialise the plugin and define global options
==============================================================================*/
init = function (options) {

// Default settings
settings = {
method: 'drawer', // Method options are drawer, modal, and flip. Default is drawer.
formSelector: 'form[action^="/cart/add"]',
addToCartSelector: 'input[type="submit"]',
cartCountSelector: null,
cartCostSelector: null,
toggleCartButton: null,
btnClass: null,
wrapperClass: null,
useCartTemplate: false,
moneyFormat: '{% raw %}${{amount}}{% endraw %}',
disableAjaxCart: false,
enableQtySelectors: true,
prependDrawerTo: 'body',
onToggleCallback: null
};

// Override defaults with arguments
$.extend(settings, options);

// Make sure method is lower case
settings.method = settings.method.toLowerCase();

// Select DOM elements
$formContainer = $(settings.formSelector);
$btnClass = settings.btnClass;
$wrapperClass = settings.wrapperClass;
$addToCart = $formContainer.find(settings.addToCartSelector);
$flipContainer = null;
$flipClose = null;
$cartCountSelector = $(settings.cartCountSelector);
$cartCostSelector = $(settings.cartCostSelector);
$toggleCartButton = $(settings.toggleCartButton);
$modal = null;
$prependDrawerTo = $(settings.prependDrawerTo);

// CSS Checks
$cssTransforms = Modernizr.csstransforms;
$cssTransforms3d = Modernizr.csstransforms3d;

// General Selectors
$w = $(window);
$body = $('body');
$html = $('html');

// Track cart activity status
isUpdating = false;

// Check if we can use .load
$nojQueryLoad = $html.hasClass('lt-ie9');
if ($nojQueryLoad) {
settings.useCartTemplate = false;
}

// Setup ajax quantity selectors on the any template if enableQtySelectors is true
if (settings.enableQtySelectors) {
qtySelectors();
}

// Enable the ajax cart
if (!settings.disableAjaxCart) {
// Handle each case add to cart method
switch (settings.method) {
case 'flip':
flipSetup();
break;

case 'modal':
modalSetup();
break;

case 'drawer':
drawerSetup();
break;
}

// Escape key closes cart
$(document).keyup( function (evt) {
if (evt.keyCode == 27) {
switch (settings.method) {
case 'flip':
case 'drawer':
hideDrawer();
break;
case 'modal':
hideModal();
break;
}
}
});

if ( $addToCart.length ) {
// Take over the add to cart form submit
formOverride();
}
}

// Run this function in case we're using the quantity selector outside of the cart
adjustCart();
};

updateCountPrice = function (cart) {
if ($cartCountSelector) {
$cartCountSelector.html(cart.item_count).removeClass('hidden-count');

if (cart.item_count === 0) {
$cartCountSelector.addClass('hidden-count');
}
}
if ($cartCostSelector) {
$cartCostSelector.html(Shopify.formatMoney(cart.total_price, settings.moneyFormat));
}
};

flipSetup = function () {
// Build and append the drawer in the DOM
drawerSetup();

// Stop if there is no add to cart button
if ( !$addToCart.length ) {
return
}

// Wrap the add to cart button in a div
$addToCart.addClass('flip-front').wrap('<div class="flip"></div>');

// Write a (hidden) Checkout button, a loader, and the extra view cart button
var checkoutBtn = $('<a href="/cart" class="flip-back" style="background-color: #C00; color: #fff;" id="flip-checkout">' + {{ 'cart.general.checkout' | t | json }} + '</a>').addClass($btnClass),
flipLoader = $('<span class="ajaxifyCart-loader"></span>'),
flipExtra = $('<div class="flip-extra">' + {{ 'cart.general.or' | t | json }} + ' <a href="#" class="flip-cart">' + {{ 'cart.general.view_cart' | t | json }} + ' (<span></span>)</a></div>');

// Append checkout button and loader
checkoutBtn.insertAfter($addToCart);
flipLoader.insertAfter(checkoutBtn);

// Setup new selectors
$flipContainer = $('.flip');

if (!$cssTransforms3d) {
$flipContainer.addClass('no-transforms')
}

// Setup extra selectors once appended
flipExtra.insertAfter($flipContainer);
$flipCart = $('.flip-cart');

$flipCart.on('click', function(e) {
e.preventDefault();
showDrawer(true);
});

// Reset the button if a user changes a variation
$('input[type="checkbox"], input[type="radio"], select', $formContainer).on('click', function() {
revertFlipButton();
})
};

revertFlipButton = function () {
$flipContainer.removeClass('is-flipped');
};

modalSetup = function () {
// Create modal DOM elements with handlebars.js template
var source = $("#modalTemplate").html(),
template = Handlebars.compile(source);

// Append modal and overlay to body
$body.append(template).append('<div id="ajaxifyCart-overlay"></div>');

// Modal selectors
$modalContainer = $('#ajaxifyModal');
$modalOverlay = $('#ajaxifyCart-overlay');
$cartContainer = $('#ajaxifyCart');

// Close modal when clicking the overlay
$modalOverlay.on('click', hideModal);

// Create a close modal button
$modalContainer.prepend('<button class="ajaxifyCart--close" title="' + {{ 'cart.general.close_cart' | t | json }} + '">' + {{ 'cart.general.close_cart' | t | json }} + '</button>');
$closeCart = $('.ajaxifyCart--close');
$closeCart.on('click', hideModal);

// Add a class if CSS translate isn't available
if (!$cssTransforms) {
$modalContainer.addClass('no-transforms')
}

// Update modal position on screen changes
$(window).on({
orientationchange: function(e) {
if ($modalContainer.hasClass('is-visible')) {
sizeModal('resize');
}
}, resize: function(e) {
// IE8 fires this when overflow on body is changed. Ignore IE8.
if (!$nojQueryLoad && $modalContainer.hasClass('is-visible')) {
sizeModal('resize');
}
}
});

// Toggle modal with cart button
setToggleButtons();
};

showModal = function (toggle) {
$body.addClass('ajaxify-modal--visible');
// Build the cart if it isn't already there
if ( !cartInit && toggle ) {
Shopify.getCart(cartUpdateCallback);
} else {
sizeModal();
}
};

sizeModal = function(isResizing) {
if (!isResizing) {
$modalContainer.css('opacity', 0);
}

// Position modal by negative margin
$modalContainer.css({
'margin-left': - ($modalContainer.outerWidth() / 2),
'opacity': 1
});

$modalContainer.addClass('is-visible');

scrollTop();

toggleCallback({
'is_visible': true
});
};

hideModal = function (e) {
$body.removeClass('ajaxify-modal--visible');
if (e) {
e.preventDefault();
}

if ($modalContainer) {
$modalContainer.removeClass('is-visible');
$body.removeClass('ajaxify-lock');
}

toggleCallback({
'is_visible': false
});
};

drawerSetup = function () {
// Create drawer DOM elements with handlebars.js template
var source = $("#drawerTemplate").html(),
template = Handlebars.compile(source),
data = {
wrapperClass: $wrapperClass
};

// Append drawer (defaults to body)
$prependDrawerTo.prepend(template(data));

// Drawer selectors
$drawerContainer = $('#ajaxifyDrawer');
$cartContainer = $('#ajaxifyCart');
$drawerCaret = $('.ajaxifyDrawer-caret > span');

// Toggle drawer with cart button
setToggleButtons();

// Position caret and size drawer on resize if drawer is visible
var timeout;
$(window).resize(function() {
clearTimeout(timeout);
timeout = setTimeout(function(){
if ($drawerContainer.hasClass('is-visible')) {
positionCaret();
sizeDrawer();
}
}, 500);
});

// Position the caret the first time
positionCaret();

// Position the caret
function positionCaret() {
if ($toggleCartButton.offset()) {
// Get the position of the toggle button to align the carat with
var togglePos = $toggleCartButton.offset(),
toggleWidth = $toggleCartButton.outerWidth(),
toggleMiddle = togglePos.left + toggleWidth/2;

$drawerCaret.css('left', toggleMiddle + 'px');
}
}
};

showDrawer = function (toggle) {
// If we're toggling with the flip method, use a special callback
if (settings.method == 'flip') {
Shopify.getCart(flipCartUpdateCallback);
}
// opening the drawer for the first time
else if ( !cartInit && toggle) {
Shopify.getCart(cartUpdateCallback);
}
// simple toggle? just size it
else if ( cartInit && toggle ) {
sizeDrawer();
}

// Show the drawer
$drawerContainer.addClass('is-visible');

scrollTop();

toggleCallback({
'is_visible': true
});
};

hideDrawer = function () {
$drawerContainer.removeAttr('style').removeClass('is-visible');
scrollTop();
toggleCallback({
'is_visible': false
});
};

sizeDrawer = function ($empty) {
if ($empty) {
$drawerContainer.css('height', '0px');
} else {
$drawerHeight = $cartContainer.outerHeight();
$('.cart-row img').css('width', 'auto'); // fix Chrome image size bug
$drawerContainer.css('height', $drawerHeight + 'px');
}
};

loadCartImages = function () {
// Size cart once all images are loaded
var cartImages = $('img', $cartContainer),
count = cartImages.length,
index = 0;

cartImages.on('load', function() {
index++;

if (index==count) {
switch (settings.method) {
case 'modal':
sizeModal();
break;
case 'flip':
case 'drawer':
sizeDrawer();
break;
}
}
});
};

formOverride = function () {
$formContainer.submit(function(e) {
e.preventDefault();

// Add class to be styled if desired
$addToCart.removeClass('is-added').addClass('is-adding');

// Remove any previous quantity errors
$('.qty-error').remove();

Shopify.addItemFromForm(e.target, itemAddedCallback, itemErrorCallback);

// Set the flip button to a loading state
switch (settings.method) {
case 'flip':
$flipContainer.addClass('flip--is-loading');
break;
}
});
};

itemAddedCallback = function (product) {
$addToCart.removeClass('is-adding').addClass('is-added');

// Slight delay of flip to mimic a longer load
switch (settings.method) {
case 'flip':
setTimeout(function () {
$flipContainer.removeClass('flip--is-loading').addClass('is-flipped');
}, 600);
break;
}
Shopify.getCart(cartUpdateCallback);
};

itemErrorCallback = function (XMLHttpRequest, textStatus) {
switch (settings.method) {
case 'flip':
$flipContainer.removeClass('flip--is-loading');
break;
}

var data = eval('(' + XMLHttpRequest.responseText + ')');
if (!!data.message) {
if (data.status == 422) {
$formContainer.after('<div class="errors qty-error">'+ data.description +'</div>')
}
}
};

cartUpdateCallback = function (cart) {
// Update quantity and price
updateCountPrice(cart);

switch (settings.method) {
case 'flip':
$('.flip-cart span').html(cart.item_count);
break;
case 'modal':
buildCart(cart);
break;
case 'drawer':
buildCart(cart);
if ( !$drawerContainer.hasClass('is-visible') ) {
showDrawer();
} else {
scrollTop();
}
break;
}
};

setToggleButtons = function () {
// Reselect the element in case it just loaded
$toggleCartButton = $(settings.toggleCartButton);

if ($toggleCartButton) {
// Turn it off by default, in case it's initialized twice
$toggleCartButton.off('click');

// Toggle the cart, based on the method
$toggleCartButton.on('click', function(e) {
e.preventDefault();

switch (settings.method) {
case 'modal':
if ( $modalContainer.hasClass('is-visible') ) {
hideModal();
} else {
showModal(true);
}
break;
case 'drawer':
case 'flip':
if ( $drawerContainer.hasClass('is-visible') ) {
hideDrawer();
} else {
showDrawer(true);
}
break;
}

});

}
};

flipCartUpdateCallback = function (cart) {
buildCart(cart);
};

buildCart = function (cart) {
// Empty cart if using default layout or not using the .load method to get /cart
if (!settings.useCartTemplate || cart.item_count === 0) {
$cartContainer.empty();
}

// Show empty cart
if (cart.item_count === 0) {
$cartContainer.append('<h2>' + {{ 'cart.general.empty' | t | json }} + '</h2><span>' + {{ 'cart.general.continue_browsing_html' | t | json }} + '</span>');

switch (settings.method) {
case 'modal':
sizeModal('resize');
break;
case 'flip':
case 'drawer':
sizeDrawer();

if (!$drawerContainer.hasClass('is-visible') && cartInit) {
sizeDrawer(true);
}
break;
}
return;
}

// Use the /cart template, or Handlebars.js layout based on theme settings
if (settings.useCartTemplate) {
cartTemplate(cart);
return;
}

// Handlebars.js cart layout
var items = [],
item = {},
data = {};

var source = $("#cartTemplate").html(),
template = Handlebars.compile(source);

// Add each item to our handlebars.js data
$.each(cart.items, function(index, cartItem) {

var itemAdd = cartItem.quantity + 1,
itemMinus = cartItem.quantity - 1,
itemQty = cartItem.quantity + ' x';

/* Hack to get product image thumbnail
* - Remove file extension, add _small, and re-add extension
* - Create server relative link
*/
var prodImg = cartItem.image.replace(/(\.[^.]*)$/, "_small$1").replace('http:', '');
var prodName = cartItem.title.replace(/(\-[^-]*)$/, "");
var prodVariation = cartItem.title.replace(/^[^\-]*/, "").replace(/-/, "");

// Create item's data object and add to 'items' array
item = {
id: cartItem.variant_id,
line: index + 1, // Shopify uses a 1+ index in the API
url: cartItem.url,
img: prodImg,
name: prodName,
variation: prodVariation,
itemAdd: itemAdd,
itemMinus: itemMinus,
itemQty: itemQty,
price: Shopify.formatMoney(cartItem.price, settings.moneyFormat)
};

items.push(item);
});

// Gather all cart data and add to DOM
data = {
items: items,
totalPrice: Shopify.formatMoney(cart.total_price, settings.moneyFormat),
btnClass: $btnClass
}
$cartContainer.append(template(data));

// With new elements we need to relink the adjust cart functions
adjustCart();

// Setup close modal button and size drawer
switch (settings.method) {
case 'modal':
loadCartImages();
break;
case 'flip':
case 'drawer':
if (cart.item_count > 0) {
loadCartImages();
} else {
sizeDrawer(true);
}
break;
default:
break;
}

// Mark the cart as built
cartInit = true;
};

cartTemplate = function (cart) {
$cartContainer.load('/cart form[action="/cart"]', function() {

// With new elements we need to relink the adjust cart functions
adjustCart();

// Size drawer at this point
switch (settings.method) {
case 'modal':
loadCartImages();
break;
case 'flip':
case 'drawer':
if (cart.item_count > 0) {
loadCartImages();
} else {
sizeDrawer(true);
}
break;
default:
break;
}

// Mark the cart as built
cartInit = true;
});
}

adjustCart = function () {
// This function runs on load, and when the cart is reprinted

// Create ajax friendly quantity fields and remove links in the ajax cart
if (settings.useCartTemplate) {
createQtySelectors();
}

// Prevent cart from being submitted while quantities are changing
$body.on('submit', 'form.cart-form', function(evt) {
if (isUpdating) {
evt.preventDefault();
}
});

// Update quantify selectors
var qtyAdjust = $('.ajaxifyCart--qty span');

// Add or remove from the quantity
qtyAdjust.off('click');
qtyAdjust.on('click', function() {
var el = $(this),
line = el.data('line'),
qtySelector = el.siblings('.ajaxifyCart--num'),
qty = parseInt( qtySelector.val() );

qty = validateQty(qty);

// Add or subtract from the current quantity
if (el.hasClass('ajaxifyCart--add')) {
qty = qty + 1;
} else {
qty = qty <= 0 ? 0 : qty - 1;
}

// If it has a data-line, update the cart.
// Otherwise, just update the input's number
if (line) {
updateQuantity(line, qty);
} else {
qtySelector.val(qty);
}

});

// Update quantity based on input on change
var qtyInput = $('.ajaxifyCart--num');
qtyInput.off('change');
qtyInput.on('change', function() {
var el = $(this),
line = el.data('line'),
qty = el.val();

// Make sure we have a valid integer
if( (parseFloat(qty) == parseInt(qty)) && !isNaN(qty) ) {
// We have a number!
} else {
// Not a number. Default to 1.
el.val(1);
return;
}

// If it has a data-line, update the cart
if (line) {
updateQuantity(line, qty);
}
});

// Highlight the text when focused
qtyInput.off('focus');
qtyInput.on('focus', function() {
var el = $(this);
setTimeout(function() {
el.select();
}, 50);
});

// Completely remove product
$('.ajaxifyCart--remove').on('click', function(e) {
var el = $(this),
line = el.data('line') || null,
qty = 0;

// Without a data-line, let the default link action take over
if (!line) {
return;
}

e.preventDefault();
updateQuantity(line, qty);
});

function updateQuantity(line, qty) {
isUpdating = true;

// Add activity classes when changing cart quantities
if (!settings.useCartTemplate) {
var row = $('.ajaxifyCart--row[data-line="' + line + '"]').addClass('ajaxifyCart--is-loading');
} else {
var row = $('.cart-row[data-line="' + line + '"]').addClass('ajaxifyCart--is-loading');
}

if ( qty === 0 ) {
row.addClass('is-removed');
}

// Slight delay to make sure removed animation is done
setTimeout(function() {
Shopify.changeItem(line, qty, adjustCartCallback);
}, 250);
}

// Save note anytime it's changed
var noteArea = $('textarea[name="note"]');
noteArea.off('change');
noteArea.on('change', function() {
var newNote = $(this).val();

// Simply updating the cart note in case they don't click update/checkout
Shopify.updateCartNote(newNote, function(cart) {});
});
if (typeof GoogleWalletButton === "function") GoogleWalletButton();
if (typeof AmazonPaymentsPayButton === "function") AmazonPaymentsPayButton();
};

adjustCartCallback = function (cart) {
isUpdating = false;

// Update quantity and price
updateCountPrice(cart);

// Hide the modal or drawer if we're at 0 items
if ( cart.item_count === 0 ) {
// Handle each add to cart method
switch (settings.method) {
case 'modal':
break;
case 'flip':
case 'drawer':
hideDrawer();
break;
}
}

// Reprint cart on short timeout so you don't see the content being removed
setTimeout(function() {
Shopify.getCart(buildCart);
}, 150)
};

createQtySelectors = function() {
// If there is a normal quantity number field in the ajax cart, replace it with our version
if ($('input[type="number"]', $cartContainer).length) {
$('input[type="number"]', $cartContainer).each(function() {
var el = $(this),
currentQty = parseInt(el.val());

var itemAdd = currentQty + 1,
itemMinus = currentQty - 1,
itemQty = currentQty + ' x';

var source = $("#ajaxifyQty").html(),
template = Handlebars.compile(source),
data = {
line: el.attr('data-line'),
itemQty: itemQty,
itemAdd: itemAdd,
itemMinus: itemMinus
};

// Append new quantity selector then remove original
el.after(template(data)).remove();
});
}

// If there is a regular link to remove an item, add attributes needed to ajaxify it
if ($('a[href^="/cart/change"]', $cartContainer).length) {
$('a[href^="/cart/change"]', $cartContainer).each(function() {
var el = $(this).addClass('ajaxifyCart--remove');
});
}
};

qtySelectors = function() {
// Change number inputs to JS ones, similar to ajax cart but without API integration.
// Make sure to add the existing name and id to the new input element
var numInputs = $('input[type="number"]');

// Qty selector has a minimum of 1 on the product page
// and 0 in the cart (determined on qty click)
var qtyMin = 0;

if (numInputs.length) {
numInputs.each(function() {
var el = $(this),
currentQty = parseInt(el.val()),
inputName = el.attr('name'),
inputId = el.attr('id');

var itemAdd = currentQty + 1,
itemMinus = currentQty - 1,
itemQty = currentQty;

var source = $("#jsQty").html(),
template = Handlebars.compile(source),
data = {
id: el.data('id'),
itemQty: itemQty,
itemAdd: itemAdd,
itemMinus: itemMinus,
inputName: inputName,
inputId: inputId
};

// Append new quantity selector then remove original
el.after(template(data)).remove();
});

// Setup listeners to add/subtract from the input
$('.js--qty-adjuster').on('click', function() {
var el = $(this),
id = el.data('id'),
qtySelector = el.siblings('.js--num'),
qty = parseInt( qtySelector.val() );

var qty = validateQty(qty);
qtyMin = $body.hasClass('template-product') ? 1 : qtyMin;

// Add or subtract from the current quantity
if (el.hasClass('js--add')) {
qty = qty + 1;
} else {
qty = qty <= qtyMin ? qtyMin : qty - 1;
}

// Update the input's number
qtySelector.val(qty);
});
}
};

scrollTop = function () {
if ($body.scrollTop() > 0 || $html.scrollTop() > 0) {
$('html, body').animate({
scrollTop: 0
}, 250, 'swing');
}
};

toggleCallback = function (data) {
// Run the callback if it's a function
if (typeof settings.onToggleCallback == 'function') {
settings.onToggleCallback.call(this, data);
}
};

validateQty = function (qty) {
if((parseFloat(qty) == parseInt(qty)) && !isNaN(qty)) {
// We have a valid number!
return qty;
} else {
// Not a number. Default to 1.
return 1;
}
};

module = {
init: init
};

return module;

}(ajaxifyShopify || {}, jQuery));

 

jam_chan
Shopify Partner
927 23 190

This is an accepted solution.

I found the solution in another thread. Just set 'inventory_policy' to 'continue' and it'll be fine. 

BYOB - Build Your Own Bundles, SPO - SEO App to research keywords & edit social link preview