Skip to content

Instantly share code, notes, and snippets.

@clickdees
Forked from marioloncarek/ajax-cart.js
Created July 31, 2020 00:56
Show Gist options
  • Save clickdees/cb0b879f3b8f6b7712832c235b7df88f to your computer and use it in GitHub Desktop.
Save clickdees/cb0b879f3b8f6b7712832c235b7df88f to your computer and use it in GitHub Desktop.

Revisions

  1. @marioloncarek marioloncarek created this gist Sep 26, 2018.
    218 changes: 218 additions & 0 deletions ajax-cart.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,218 @@
    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();
    });
    57 changes: 57 additions & 0 deletions ajax-cart.liquid
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,57 @@
    <!--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-->
    151 changes: 151 additions & 0 deletions ajax-cart.scss
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,151 @@
    .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;
    }

    }
    10 changes: 10 additions & 0 deletions drawer-trigger-liquid
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    <!--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-->
    106 changes: 106 additions & 0 deletions single-product-form.liquid
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,106 @@
    <!--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-->