-
-
Save KhalilAhmadDanish/00779668117d346579c7f0ceed2d6fc7 to your computer and use it in GitHub Desktop.
complete shopify ajax cart solution with drawer and modal, adding and removing products - ugly AF
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const defaults = { | |
cartModal: '.js-ajax-cart-modal', // classname | |
cartModalContent: '.js-ajax-cart-modal-content', // classname | |
cartModalClose: '.js-ajax-cart-modal-close', // classname | |
cartDrawer: '.js-ajax-cart-drawer', // classname | |
cartDrawerContent: '.js-ajax-cart-drawer-content', // classname | |
cartDrawerClose: '.js-ajax-cart-drawer-close', // classname | |
cartDrawerTrigger: '.js-ajax-cart-drawer-trigger', // classname | |
cartOverlay: '.js-ajax-cart-overlay', // classname | |
cartCounter: '.js-ajax-cart-counter', // classname | |
addToCart: '.js-ajax-add-to-cart', // classname | |
removeFromCart: '.js-ajax-remove-from-cart', //classname | |
removeFromCartNoDot: 'js-ajax-remove-from-cart', //classname, | |
checkoutButton: '.js-ajax-checkout-button', | |
}; | |
const cartModal = document.querySelector(defaults.cartModal); | |
const cartModalContent = document.querySelector(defaults.cartModalContent); | |
const cartModalClose = document.querySelector(defaults.cartModalClose); | |
const cartDrawer = document.querySelector(defaults.cartDrawer); | |
const cartDrawerContent = document.querySelector(defaults.cartDrawerContent); | |
const cartDrawerClose = document.querySelector(defaults.cartDrawerClose); | |
const cartDrawerTrigger = document.querySelector(defaults.cartDrawerTrigger); | |
const cartOverlay = document.querySelector(defaults.cartOverlay); | |
const cartCounter = document.querySelector(defaults.cartCounter); | |
const addToCart = document.querySelectorAll(defaults.addToCart); | |
let removeFromCart = document.querySelectorAll(defaults.removeFromCart); | |
const checkoutButton = document.querySelector(defaults.checkoutButton); | |
const htmlSelector = document.documentElement; | |
for (let i = 0; i < addToCart.length; i++) { | |
addToCart[i].addEventListener('click', function(event) { | |
event.preventDefault(); | |
const formID = this.parentNode.getAttribute('id'); | |
console.log(formID); | |
addProductToCart(formID); | |
}); | |
} | |
function addProductToCart(formID) { | |
$.ajax({ | |
type: 'POST', | |
url: '/cart/add.js', | |
dataType: 'json', | |
data: $('#' + formID) | |
.serialize(), | |
success: addToCartOk, | |
error: addToCartFail, | |
}); | |
} | |
function fetchCart() { | |
$.ajax({ | |
type: 'GET', | |
url: '/cart.js', | |
dataType: 'json', | |
success: function(cart) { | |
onCartUpdate(cart); | |
if (cart.item_count === 0) { | |
cartDrawerContent.innerHTML = 'Cart is empty'; | |
checkoutButton.classList.add('is-hidden'); | |
} else { | |
renderCart(cart); | |
checkoutButton.classList.remove('is-hidden'); | |
} | |
}, | |
}); | |
} | |
function changeItem(line, callback) { | |
const quantity = 0; | |
$.ajax({ | |
type: 'POST', | |
url: '/cart/change.js', | |
data: 'quantity=' + quantity + '&line=' + line, | |
dataType: 'json', | |
success: function(cart) { | |
if ((typeof callback) === 'function') { | |
callback(cart); | |
} else { | |
onCartUpdate(cart); | |
fetchCart(); | |
removeProductFromCart(); | |
} | |
}, | |
}); | |
} | |
function onCartUpdate(cart) { | |
console.log('items in the cart?', cart.item_count); | |
} | |
function addToCartOk(product) { | |
cartModalContent.innerHTML = product.title + ' was added to the cart!'; | |
cartCounter.innerHTML = Number(cartCounter.innerHTML) + 1; | |
openAddModal(); | |
openCartOverlay(); | |
fetchCart(); | |
} | |
function removeProductFromCart() { | |
cartCounter.innerHTML = Number(cartCounter.innerHTML) - 1; | |
} | |
function addToCartFail() { | |
cartModalContent.innerHTML = 'The product you are trying to add is out of stock.'; | |
openAddModal(); | |
openCartOverlay(); | |
} | |
function renderCart(cart) { | |
console.log(cart); | |
clearCartDrawer(); | |
cart.items.forEach(function(item, index) { | |
//console.log(item.title); | |
//console.log(item.image); | |
//console.log(item.line_price); | |
//console.log(item.quantity); | |
const productTitle = '<div class="ajax-cart-item__title">' + item.title + '</div>'; | |
const productImage = '<img class="ajax-cart-item__image" src="' + item.image + '" >'; | |
const productPrice = '<div class="ajax-cart-item__price">' + item.line_price + '</div>'; | |
const productQuantity = '<div class="ajax-cart-item__quantity">' + item.quantity + '</div>'; | |
const productRemove = '<div class="ajax-cart-item__remove ' + defaults.removeFromCartNoDot + '"></div>'; | |
const concatProductInfo = '<div class="ajax-cart-item__single" data-line="' + Number(index + 1) + '">' + productTitle + productImage + productPrice + productQuantity + productRemove + '</div>'; | |
cartDrawerContent.innerHTML = cartDrawerContent.innerHTML + concatProductInfo; | |
}); | |
// document.querySelectorAll('.js-ajax-remove-from-cart') | |
// .forEach((element) => { | |
// element.addEventListener('click', function() { | |
// const lineID = this.parentNode.getAttribute('data-line'); | |
// console.log('aa'); | |
// }); | |
// }); | |
removeFromCart = document.querySelectorAll(defaults.removeFromCart); | |
for (let i = 0; i < removeFromCart.length; i++) { | |
removeFromCart[i].addEventListener('click', function() { | |
const line = this.parentNode.getAttribute('data-line'); | |
console.log(line); | |
changeItem(line); | |
}); | |
} | |
} | |
function openCartDrawer() { | |
cartDrawer.classList.add('is-open'); | |
} | |
function closeCartDrawer() { | |
cartDrawer.classList.remove('is-open'); | |
} | |
function clearCartDrawer() { | |
cartDrawerContent.innerHTML = ''; | |
} | |
function openAddModal() { | |
cartModal.classList.add('is-open'); | |
} | |
function closeAddModal() { | |
cartModal.classList.remove('is-open'); | |
} | |
function openCartOverlay() { | |
cartOverlay.classList.add('is-open'); | |
htmlSelector.classList.add('is-locked'); | |
} | |
function closeCartOverlay() { | |
cartOverlay.classList.remove('is-open'); | |
htmlSelector.classList.remove('is-locked'); | |
} | |
cartModalClose.addEventListener('click', function() { | |
closeAddModal(); | |
closeCartOverlay(); | |
}); | |
cartDrawerClose.addEventListener('click', function() { | |
closeCartDrawer(); | |
closeCartOverlay(); | |
}); | |
// cart is empty stanje | |
cartOverlay.addEventListener('click', function() { | |
closeAddModal(); | |
closeCartDrawer(); | |
closeCartOverlay(); | |
}); | |
cartDrawerTrigger.addEventListener('click', function(event) { | |
event.preventDefault(); | |
//fetchCart(); | |
openCartDrawer(); | |
openCartOverlay(); | |
}); | |
document.addEventListener('DOMContentLoaded', function() { | |
fetchCart(); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--ajax cart modal--> | |
<div class="ajax-cart__modal js-ajax-cart-modal"> | |
<div class="ajax-cart-modal"> | |
<!--ajax cart modal close--> | |
<div class="ajax-cart-modal__close js-ajax-cart-modal-close"> | |
{% include 'icon-close' %} | |
</div> | |
<!--end ajax cart modal close--> | |
<!--ajax cart modal content--> | |
<div class="ajax-cart-modal__content js-ajax-cart-modal-content"></div> | |
<!--end ajax cart modal content--> | |
</div> | |
</div> | |
<!--end ajax cart modal--> | |
<!--ajax cart drawer--> | |
<div class="ajax-cart__drawer js-ajax-cart-drawer"> | |
<div class="ajax-cart-drawer"> | |
<!--ajax cart drawer close--> | |
<div class="ajax-cart-drawer__close js-ajax-cart-drawer-close"> | |
{% include 'icon-close' %} | |
</div> | |
<!--end ajax cart drawer close--> | |
<!--ajax cart drawer content--> | |
<div class="ajax-cart-drawer__content js-ajax-cart-drawer-content"></div> | |
<!--end ajax cart drawer content--> | |
<!--ajax cart drawer buttons--> | |
<div class="ajax-cart-drawer__buttons"> | |
<a href="/cart/" class="button button--black button--full-width js-button"> | |
<span>Go to cart</span> | |
</a> | |
<a href="/checkout/" class="button button--black button--full-width js-button js-ajax-checkout-button"> | |
<span>Proceed to checkout</span> | |
</a> | |
</div> | |
<!--end ajax cart drawer buttons--> | |
</div> | |
</div> | |
<!--end ajax cart drawer--> | |
<!--ajax cart overlay--> | |
<div class="ajax-cart__overlay js-ajax-cart-overlay"></div> | |
<!--end ajax cart overlay--> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.ajax-cart { | |
&__modal { | |
position: fixed; | |
top: 50%; | |
left: 50%; | |
transform: translate(-50%, -50%); | |
z-index: 40; | |
max-width: 575px; | |
background: getColor('white', 'default'); | |
border: 1px solid #e9e9e9; | |
padding: 50px 65px; | |
opacity: 0; | |
visibility: hidden; | |
will-change: opacity, visibility; | |
&.is-open { | |
opacity: 1; | |
visibility: visible; | |
} | |
} | |
&__overlay { | |
position: fixed; | |
z-index: 30; | |
top: 0; | |
bottom: 0; | |
left: 0; | |
right: 0; | |
background-color: getColor('black-40', 'variations'); | |
opacity: 0; | |
visibility: hidden; | |
will-change: opacity, visibility; | |
&.is-open { | |
opacity: 1; | |
visibility: visible; | |
} | |
} | |
&__drawer { | |
transition: getTransition(); | |
position: fixed; | |
z-index: 40; | |
right: -400px; | |
top: 0; | |
width: 400px; | |
height: 100%; | |
background: #f6f6f6; | |
will-change: transform; | |
border-left: 1px solid #e9e9e9; | |
&.is-open { | |
transform: translateX(-100%); | |
} | |
} | |
} | |
.ajax-cart-modal { | |
position: relative; | |
&__close { | |
position: absolute; | |
right: 10px; | |
top: 10px; | |
} | |
&__content { | |
padding: 20px; | |
} | |
} | |
.ajax-cart-drawer { | |
position: relative; | |
height: 100%; | |
&__close { | |
position: absolute; | |
right: 10px; | |
top: 5px; | |
} | |
&__content { | |
padding: 25px 25px 190px; | |
height: 100%; | |
overflow: hidden; | |
overflow-y: scroll; | |
} | |
&__buttons { | |
position: absolute; | |
z-index: 10; | |
left: 0; | |
bottom: 0; | |
width: 100%; | |
height: 190px; | |
background: #f6f6f6; | |
padding: 20px; | |
display: flex; | |
flex-direction: column; | |
justify-content: flex-end; | |
.button { | |
&:last-child { | |
margin-top: auto; | |
} | |
} | |
} | |
} | |
.ajax-cart-item { | |
&__single { | |
position: relative; | |
margin-bottom: 20px; | |
border-bottom: 2px solid red; | |
} | |
&__title { | |
} | |
&__image { | |
width: 100px; | |
} | |
&__price { | |
} | |
&__quantity { | |
} | |
&__remove { | |
@include center(vertical); | |
right: 5px; | |
width: 15px; | |
height: 15px; | |
background: url('data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiBpY29uLWNsb3NlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCIgdmlld0JveD0iMCAwIDIwIDIwIj4KICAgIDxwYXRoIGQ9Ik0xNS44OSAxNC42OTZsLTQuNzM0LTQuNzM0IDQuNzE3LTQuNzE3Yy40LS40LjM3LTEuMDg1LS4wMy0xLjQ4NXMtMS4wODUtLjQzLTEuNDg1LS4wM0w5LjY0MSA4LjQ0NyA0Ljk3IDMuNzc2Yy0uNC0uNC0xLjA4NS0uMzctMS40ODUuMDNzLS40MyAxLjA4NS0uMDMgMS40ODVsNC42NzEgNC42NzEtNC42ODggNC42ODhjLS40LjQtLjM3IDEuMDg1LjAzIDEuNDg1czEuMDg1LjQzIDEuNDg1LjAzbDQuNjg4LTQuNjg3IDQuNzM0IDQuNzM0Yy40LjQgMS4wODUuMzcgMS40ODUtLjAzcy40My0xLjA4NS4wMy0xLjQ4NXoiLz4KPC9zdmc+Cg==') center no-repeat; | |
background-size: cover; | |
cursor: pointer; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--cart--> | |
<div class="header__cart"> | |
<a class="js-ajax-cart-drawer-trigger" href="/cart"> | |
{% include 'icon-cart' %} | |
<span class="js-ajax-cart-counter">{{ cart.item_count }}</span> | |
</a> | |
</div> | |
<!--end cart--> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!--product form--> | |
<form action="/cart/add" method="post" enctype="multipart/form-data" id="add-to-cart-{{ product.handle }}"> | |
<!--product variants--> | |
{% unless product.has_only_default_variant %} | |
{% for option in product.options_with_values %} | |
<div class="single-product__option-wrapper js"> | |
{% assign option-name = option.name | downcase %} | |
<div class="js-single-product-option-{{ option-name }} single-product-option-{{ option-name }}" | |
id="SingleOptionSelector-{{ forloop.index0 }}"> | |
{% for value in option.values %} | |
{% assign product-handle = product.handle %} | |
{% assign is_color = false %} | |
{% assign stripped-value = value | split: ' ' | last | handle %} | |
{% if option-name contains 'color' or option-name contains 'colour' %} | |
{% assign is_color = true %} | |
{% endif %} | |
{% if is_color %} | |
<input type="radio" name="{{ option-name }}-{{ product-handle }}" | |
class="single-option-selector single-product-option-{{ option-name }}__input js-radio-button" | |
data-single-option-selector | |
data-index="option{{ option.position }}" | |
value="{{ value | escape }}" | |
data-color="{{ value | handleize }}" | |
{% if option.selected_value == value %}checked="checked"{% endif %} | |
id="variant_{{ option-name }}-{{ product-handle }}-{{ forloop.index0 }}"/> | |
<label for="variant_{{ option-name }}-{{ product-handle }}-{{ forloop.index0 }}" | |
class="single-product-option-{{ option-name }}__label {% if stripped-value contains 'white' %}single-product-option-{{ option-name }}__label--white{% endif %}" | |
style="background-color: {{ stripped-value }};"> | |
{% include 'icon-check' %} | |
</label> | |
{% else %} | |
<input type="radio" name="{{ option-name }}-{{ product-handle }}" | |
class="single-option-selector single-product-option-{{ option-name }}__input" | |
data-single-option-selector | |
data-index="option{{ option.position }}" | |
value="{{ value | escape }}" | |
{% if option.selected_value == value %}checked="checked"{% endif %} | |
id="variant_{{ option-name }}-{{ product-handle }}-{{ forloop.index0 }}"/> | |
<label for="variant_{{ option-name }}-{{ product-handle }}-{{ forloop.index0 }}" | |
class="single-product-option-{{ option-name }}__label">{{ value }}</label> | |
{% endif %} | |
{% endfor %} | |
</div> | |
</div> | |
{% endfor %} | |
{% endunless %} | |
<select name="id" class="no-js" data-product-select> | |
{% for variant in product.variants %} | |
<option | |
{% if variant == current_variant %}selected="selected"{% endif %} | |
{% unless variant.available %}disabled="disabled"{% endunless %} | |
value="{{ variant.id }}"> | |
{{ variant.title }} | |
</option> | |
{% endfor %} | |
</select> | |
<!--end product variants--> | |
<!--product add to cart--> | |
<button | |
class="single-product__add-to-cart u-b6 js-ajax-add-to-cart" | |
type="submit" | |
name="add" | |
data-add-to-cart | |
{% unless current_variant.available %}disabled="disabled"{% endunless %}> | |
<span data-add-to-cart-text> | |
{% if current_variant.available %} | |
{{ 'products.product.add_to_cart' | t }} | |
{% else %} | |
{{ 'products.product.sold_out' | t }} | |
{% endif %} | |
</span> | |
</button> | |
<!--end product add to cart--> | |
</form> | |
<!--end product form--> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment