Create a file on assets/js/theme/custom
directory.
export default class StickyAddToCart {
constructor() {
this.change = new Event('change', { bubbles: true });
this.prefix = 'opt7_';
this.adcWrapper = document.getElementById("add-to-cart-wrapper");
this.opt7Wraper = document.getElementById("opt7-quantity-box");
this.stickyElement = document.getElementById('opt7_sticky_adc');
this.qtyInput = this.adcWrapper.querySelector('input');
this.handleVisible = this.handleVisible.bind(this);
}
isElementInViewport() {
let el = this.adcWrapper;
if (typeof jQuery === "function" && el instanceof jQuery) { el = el[0]; }
let rect = el.getBoundingClientRect();
return (
rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
handleVisible() {
if (!this.isElementInViewport()) {
this.stickyElement.style.display = 'block';
} else {
this.stickyElement.style.display = 'none';
}
}
updateQty(btn, e) {
e.preventDefault();
const target = btn.getAttribute('data-action');
const duplicateInput = document.getElementById(`${this.prefix}${this.qtyInput.getAttribute('id')}`);
const quantityMin = parseInt(this.qtyInput.getAttribute('data-quantity-min'), 10);
const quantityMax = parseInt(this.qtyInput.getAttribute('data-quantity-max'), 10);
let qty = parseInt(this.qtyInput.value, 10);
// If action is incrementing
if (target === 'inc') {
// If quantity max option is set
if (quantityMax > 0) {
// Check quantity does not exceed max
if ((qty + 1) <= quantityMax) {
qty++;
}
} else {
qty++;
}
} else if (qty > 1) {
// If quantity min option is set
if (quantityMin > 0) {
// Check quantity does not fall below min
if ((qty - 1) >= quantityMin) {
qty--;
}
} else {
qty--;
}
}
this.qtyInput.value = qty;
duplicateInput.value = qty;
this.qtyInput.dispatchEvent(this.change);
}
duplicateForm() {
const originalForm= this.adcWrapper.querySelector('.form-field--increments');
const duplicateForm = originalForm.cloneNode(true);
duplicateForm.querySelectorAll('[id]').forEach((element) => {
element.id = this.prefix + element.id;
});
duplicateForm.querySelectorAll(`[data-quantity-change] button`).forEach((btn) => {
btn.addEventListener('click', (e) => {
this.updateQty(btn, e)
})
})
this.adcWrapper.querySelectorAll(`[data-quantity-change] button`).forEach((btn) => {
btn.addEventListener('click', (e) => {
this.qtyInput.dispatchEvent(this.change);
})
})
this.opt7Wraper.append(duplicateForm);
}
submitFrom(btn) {
if (btn.currentTarget.classList.value.match(/hasOptions/gi) !== null) {
if (window.innerWidth < 500) {
document.querySelector('.product-options').scrollIntoView({
behavior: 'smooth'
});
} else {
document.querySelector('#main-content').scrollIntoView({
behavior: 'smooth'
});
}
setTimeout(() => {
$('#form-action-addToCart').trigger('click');
}, 700)
} else {
document.querySelector('#main-content').scrollIntoView({
behavior: 'smooth'
});
$('#form-action-addToCart').trigger('click');
}
}
init() {
this.duplicateForm();
const duplicateInput = document.getElementById(`${this.prefix}${this.qtyInput.getAttribute('id')}`);
const events = ['change', 'keyup', 'keydown'];
const quantityInput = this.qtyInput;
window.addEventListener('load', this.handleVisible);
window.addEventListener('resize', this.handleVisible);
window.addEventListener('scroll', this.handleVisible);
document.querySelector(`#${this.stickyElement.getAttribute('id')} button.atc`).addEventListener('click', (e) => this.submitFrom(e));
events.forEach(function (event) {
quantityInput.addEventListener(event, (e) => {
setTimeout(() => {
duplicateInput.value = e.target.value
}, [100])
});
duplicateInput.addEventListener(event, (e) => {
quantityInput.value = e.target.value;
});
});
}
}
Call stickyAddToCart on assets/js/theme/common/product-details.js
file's onReady()
method.
//......
//......
import stickyAddToCart from '../custom/stickyAddToCart';
//......
//......
export default class ProductDetails extends PageManager {
constructor(context) {
super(context);
//......
}
onReady() {
//......
//......
//......
//......
const adc = new stickyAddToCart();
adc.init();
}
}
Modify this style for your design on _custom.scss
file.
.stickyAddToCart--container {
width : 100%;
height : 70px;
display : none;
position : fixed;
z-index : 999;
background-color : #FFFFFF;
bottom : 0;
left : 0;
padding : 10px;
border-top: 1px solid #c3c2c2;
box-shadow: -28px 10px 80px -19px #000000;
.product-properties {
display : flex;
flex-direction : row;
flex-wrap : nowrap;
align-content : center;
align-items : center;
justify-content : space-between;
.title {
flex : 0 1 65%;
@include breakpoint('xxsmall') {
flex : 0 1 58%;
}
@include breakpoint('medium') {
flex : 0 1 65%;
}
h2 {
margin : 0;
font-size : 20px;
font-weight : 500;
@include breakpoint('xxsmall') {
font-size : 12px;
}
@include breakpoint('medium') {
font-size : 20px;
}
}
}
.image {
flex : 0 1 5%;
@include breakpoint('xxsmall') {
flex : 0 1 10%;
display : none;
}
@include breakpoint('medium') {
flex : 0 1 5%;
display : block;
}
img {
width : 50px;
}
}
.add-to-cart {
flex : 0 1 30%;
display : flex;
flex-direction : row;
align-items : center;
@include breakpoint('xxsmall') {
flex : 0 1 40%;
justify-content: flex-end;
}
@include breakpoint('medium') {
flex : 0 1 30%;
justify-content: flex-end;
}
div#opt7-quantity-box {
flex : 0 1 40%;
@include breakpoint('xxsmall') {
flex : 0 1 50%;
}
@include breakpoint('medium') {
flex : 0 1 40%;
}
.form-field--increments {
margin-bottom : 0px;
}
.form-increment {
text-align : initial;
}
.form-field--increments .form-increment button, .form-field--increments .form-increment .form-input--incrementTotal {
border-radius : 0rem;
padding : 10px;
height : 50px;
border-color : rgb(153, 153, 153);
margin : -4px;
@include breakpoint('xxsmall') {
padding : 5px;
}
@include breakpoint('medium') {
padding : 10px;
}
}
.form-field--increments .form-increment .form-input--incrementTotal {
border-top : 1px solid rgb(153, 153, 153);
border-bottom : 1px solid rgb(153, 153, 153);
font-size : 20px;
font-weight : bold;
color : rgb(0, 0, 0);
width : 45px;
@include breakpoint('xxsmall') {
width : 32px;
}
@include breakpoint('medium') {
width : 45px;
}
}
.form-field--increments .form-increment [data-action="dec"] {
border-right : none;
}
.form-field--increments .form-increment [data-action="inc"] {
border-left : none;
}
}
button.atc {
flex : 0 1 60%;
width : 100%;
height : 52px;
border-radius : 0rem;
text-transform : uppercase;
font-weight : bold;
margin-bottom : 0px;
background : rgb(37, 60, 76);
appearance : none;
border-style : solid;
border-width : 1px;
cursor : pointer;
font-family : Montserrat, Arial, Helvetica, sans-serif;
line-height : normal;
position : relative;
text-align : center;
text-decoration : none;
display : inline-block;
font-size : 1rem;
padding : 0.85714rem 2.28571rem;
outline : none;
vertical-align : middle;
color : #FFFFFF;
@include breakpoint('xxsmall') {
flex : 0 1 50%;
font-size : 14px;
padding : 0;
height : 50px;
border : 1px solid rgb(37, 60, 76);
}
@include breakpoint('medium') {
flex : 0 1 60%;
height : 52px;
padding : 0.85714rem 2.28571rem;
font-size : 1rem;
border : 1px solid rgb(37, 60, 76);
}
span {
@include breakpoint('xxsmall') {
display : none;
}
@include breakpoint('medium') {
display : block;
}
}
i {
@include breakpoint('xxsmall') {
display : block;
font-size: 32px;
}
@include breakpoint('medium') {
display : none;
}
}
}
}
}
}
Modify templates/components/product/product-view.html
with this code block at the end of the page.
<div class="stickyAddToCart--container" id="opt7_sticky_adc">
<div class="product-properties">
<div class="image">
{{> components/common/responsive-img
image=product.main_image
class="productView-image--default"
fallback_size=theme_settings.product_size
lazyload=theme_settings.lazyload_mode
default_image=theme_settings.default_image_product
otherAttributes="data-main-image"
}}
</div>
<div class="title"><h2>{{product.title}}</h2></div>
<div class="add-to-cart">
<div id="opt7-quantity-box">
<span class="anchor"></span>
</div>
<button {{#if product.options.length '>' 0}} class="atc hasOptions" {{else}} class="atc" {{/if}}>
<span>Add to cart</span>
<i class="fa fa-cart-plus"></i>
</button>
</div>
</div>
</div>
Happy Hacking! 🧡