Skip to content

Instantly share code, notes, and snippets.

@philcon93
Last active August 2, 2017 03:41
Show Gist options
  • Save philcon93/3bb54c44beb5712452ffc2a441a0ce53 to your computer and use it in GitHub Desktop.
Save philcon93/3bb54c44beb5712452ffc2a441a0ce53 to your computer and use it in GitHub Desktop.
Validate Editable Kits

Validate Editable Kits

B@se and JS

  • Implement a custom solution done with javascript on the front-end product page to perform strict validations on the min/max values for edible kits components.
  • When the min and max are identical, it will disable and grey out the quantity box to show that the value can't be changed.
  • The “add to cart” will only be available once the user has selected the minimum components quantity set in the editable kit bundle.

Changes to components.template.html

  • Add max amount in title - [@assemble_max_qty@]
  • Wrapper around the whole components.template.html - div class="wrapper-components"
  • Change first row to - div class="row wrapper-component-group" data-max="[@assemble_max_qty@]" data-counter=""
$(document).ready(function(){
var addToCartBtn = $('.wrapper-components .addtocart');
var totalQty = 0;
$(".wrapper-component-group").each(function(){
totalQty += parseInt($(this).attr('data-max'));
});
disableCompBtn();
calculateInputAmt();
function disableCompBtn(){
$(".component-config-input").each(function(){
if (($(this).attr('max')) === ($(this).attr('min'))) {
$(this).val($(this).attr('min')).attr('disabled','disabled');
}
});
}
function disableGroupBtns(){
if($('.wrapper-component-group').attr('data-max') > 0){
$(".wrapper-component-group").each(function(){
if(parseInt($(this).attr('data-counter')) >= parseInt($(this).attr('data-max'))){
$(this).find(".component-config-input").each(function(){
if($(this).val() <= 0){
$(this).attr('disabled','disabled');
}
});
}else{
$(this).find(".component-config-input").removeAttr('disabled');
}
});
disableCompBtn();
}
}
function calculateInputAmt(){
if($('.wrapper-component-group').length <= 1){
var totalInput = 0;
$(".wrapper-component-group").find(".component-config-input").each(function(){
if (!isNaN(this.value) && this.value.length != 0) {
totalInput += parseFloat(this.value);
}
});
$(this).find($(".wrapper-component-group").attr('data-counter', totalInput));
}else{
$(".wrapper-component-group").each(function(){
var totalInput = 0;
$(this).find(".component-config-input").each(function(){
if (!isNaN(this.value) && this.value.length != 0) {
totalInput += parseFloat(this.value);
$(this).parents('.wrapper-component-group').attr('data-counter', totalInput);
}
});
});
}
addtocartBtnChange();
}
function addtocartBtnChange(){
var totalInput = 0;
if($('.wrapper-component-group').length <= 1){
var totalInput = parseInt($(".wrapper-component-group").attr('data-counter'));
}else{
$(".wrapper-component-group").each(function(){
totalInput += parseInt($(this).attr('data-counter'));
});
}
if(totalQty == 0 ){
if (parseInt(totalInput) > 0) {
addToCartBtn
.removeClass("btn-warning btn-danger")
.addClass("btn-success")
.text("Add to Cart")
.removeAttr('disabled');
}else {
addToCartBtn
.removeClass("btn-warning btn-success")
.addClass("btn-danger")
.text("Choose More Items")
.attr('disabled','disabled');
}
}else{
if (parseInt(totalInput) == parseInt(totalQty)) {
addToCartBtn
.removeClass("btn-warning btn-danger")
.addClass("btn-success")
.text("Add to Cart")
.removeAttr('disabled');
}else if (parseInt(totalInput) < parseInt(totalQty)) {
var chooseMoreQty = parseInt(totalQty) - parseInt(totalInput);
addToCartBtn
.removeClass("btn-success btn-danger")
.addClass("btn-warning")
.text("Choose "+ chooseMoreQty + " More Item(s)")
.attr('disabled','disabled');
}else {
addToCartBtn
.removeClass("btn-warning btn-success")
.addClass("btn-danger")
.text("Max of "+ totalQty + " Items")
.attr('disabled','disabled');
}
}
}
function createPopup(type, amount){
var type = type;
var amount = amount;
var popup = '<div class="stock-alert ' + type +' ">';
popup += '<div class="tooltip bottom" role="tooltip">';
popup += '<div class="tooltip-arrow"></div>';
popup += '<div class="tooltip-inner"><strong>' + amount + '</strong> is the ' + type +' this field can go</div>';
popup += '</div>';
popup += '</div>';
return popup;
}
$('.component.selector')
.on('keyup', '.components-thumbnail input', function(){
var value = parseInt($(this).val());
var intMax = parseInt($(this).attr('max'));
var popupMax = createPopup('maximum', intMax);
var intMin = parseInt($(this).attr('min'));
var popupMin = createPopup('minimum', intMin);
if(value > intMax){
if($(this).parent().find('.stock-alert.maximum').length <= 0){
$(this).parent().append(popupMax);
}
$(this).val(intMax);
}else{
$(this).parent().find('.stock-alert').remove();
}
if(value < intMin){
if($(this).parent().find('.stock-alert.minimum').length <= 0){
$(this).parent().append(popupMin);
}
addToCartBtn.attr('disabled', 'disabled');
}else{
addToCartBtn.removeAttr('disabled');
}
calculateInputAmt();
disableGroupBtns();
})
.on('focus', '.components-thumbnail input', function(){
if($(this).val() == 0){
$(this).val('');
}
})
.on('blur', '.components-thumbnail input', function(){
var value = parseInt($(this).val());
var intMin = parseInt($(this).attr('min'));
var popupMin = createPopup('minimum', intMin);
if(value < intMin){
$(this).val(intMin);
addToCartBtn.removeAttr('disabled');
}else{
$(this).parent().find('.stock-alert').remove();
addToCartBtn.removeAttr('disabled');
}
if($(this).val() == '' || isNaN(value)){
$(this).val(0);
}
calculateInputAmt();
})
.on("change", '.components-thumbnail input', function(){
calculateInputAmt();
disableGroupBtns();
});
});
/* Add these styles for tooltip */
.stock-alert.maximum .tooltip, .stock-alert.minimum .tooltip{
opacity: 1;
}
.stock-alert .tooltip-inner{
background-color: #333;
}
.stock-alert.maximum .tooltip.bottom,
.stock-alert.minimum .tooltip.bottom{
margin-top: 35px;
}
.stock-alert .tooltip-arrow{
color:#333;
}
.wrapper-components-thumbnail .input-group{
display: block;
}
$(document).ready(function(){
var addToCartBtn = $('.wrapper-components .addtocart');
var totalQty = 0;
$(".wrapper-component-group").each(function(){
totalQty += parseInt($(this).attr('data-max'));
});
disableCompBtn();
calculateInputAmt();
function disableCompBtn(){
$(".component-config-input").each(function(){
if (($(this).attr('max')) === ($(this).attr('min'))) {
$(this).val($(this).attr('min')).attr('disabled','disabled');
}
});
}
function disableGroupBtns(){
if($('.wrapper-component-group').attr('data-max') > 0){
$(".wrapper-component-group").each(function(){
if(parseInt($(this).attr('data-counter')) >= parseInt($(this).attr('data-max'))){
$(this).find(".component-config-input").each(function(){
if($(this).val() <= 0){
$(this).attr('disabled','disabled');
}
});
}else{
$(this).find(".component-config-input").removeAttr('disabled');
}
});
disableCompBtn();
}
}
function calculateInputAmt(){
if($('.wrapper-component-group').length <= 1){
var totalInput = 0;
$(".wrapper-component-group").find(".component-config-input").each(function(){
if (!isNaN(this.value) && this.value.length != 0) {
totalInput += parseFloat(this.value);
}
});
$(this).find($(".wrapper-component-group").attr('data-counter', totalInput));
}else{
$(".wrapper-component-group").each(function(){
var totalInput = 0;
$(this).find(".component-config-input").each(function(){
if (!isNaN(this.value) && this.value.length != 0) {
totalInput += parseFloat(this.value);
$(this).parents('.wrapper-component-group').attr('data-counter', totalInput);
}
});
});
}
addtocartBtnChange();
}
function addtocartBtnChange(){
var totalInput = 0;
if($('.wrapper-component-group').length <= 1){
var totalInput = parseInt($(".wrapper-component-group").attr('data-counter'));
}else{
$(".wrapper-component-group").each(function(){
totalInput += parseInt($(this).attr('data-counter'));
});
}
if(totalQty == 0 ){
if (parseInt(totalInput) > 0) {
addToCartBtn
.removeClass("btn-warning btn-danger")
.addClass("btn-success")
.text("Add to Cart")
.removeAttr('disabled');
}else {
addToCartBtn
.removeClass("btn-warning btn-success")
.addClass("btn-danger")
.text("Choose More Items")
.attr('disabled','disabled');
}
}else{
if (parseInt(totalInput) == parseInt(totalQty)) {
addToCartBtn
.removeClass("btn-warning btn-danger")
.addClass("btn-success")
.text("Add to Cart")
.removeAttr('disabled');
}else if (parseInt(totalInput) < parseInt(totalQty)) {
var chooseMoreQty = parseInt(totalQty) - parseInt(totalInput);
addToCartBtn
.removeClass("btn-success btn-danger")
.addClass("btn-warning")
.text("Choose "+ chooseMoreQty + " More Item(s)")
.attr('disabled','disabled');
}else {
addToCartBtn
.removeClass("btn-warning btn-success")
.addClass("btn-danger")
.text("Max of "+ totalQty + " Items")
.attr('disabled','disabled');
}
}
}
function createPopup(type, amount){
var type = type;
var amount = amount;
var popup = '<div class="stock-alert ' + type +' ">';
popup += '<div class="tooltip bottom" role="tooltip">';
popup += '<div class="tooltip-arrow"></div>';
popup += '<div class="tooltip-inner"><strong>' + amount + '</strong> is the ' + type +' this field can go</div>';
popup += '</div>';
popup += '</div>';
return popup;
}
$('.component.selector')
.on('keyup', '.components-thumbnail input', function(){
var value = parseInt($(this).val());
var intMax = parseInt($(this).attr('max'));
var popupMax = createPopup('maximum', intMax);
var intMin = parseInt($(this).attr('min'));
var popupMin = createPopup('minimum', intMin);
if(value > intMax){
if($(this).parent().find('.stock-alert.maximum').length <= 0){
$(this).parent().append(popupMax);
}
$(this).val(intMax);
}else{
$(this).parent().find('.stock-alert').remove();
}
if(value < intMin){
if($(this).parent().find('.stock-alert.minimum').length <= 0){
$(this).parent().append(popupMin);
}
addToCartBtn.attr('disabled', 'disabled');
}else{
addToCartBtn.removeAttr('disabled');
}
calculateInputAmt();
disableGroupBtns();
})
.on('focus', '.components-thumbnail input', function(){
if($(this).val() == 0){
$(this).val('');
}
})
.on('blur', '.components-thumbnail input', function(){
var value = parseInt($(this).val());
var intMin = parseInt($(this).attr('min'));
var popupMin = createPopup('minimum', intMin);
if(value < intMin){
$(this).val(intMin);
addToCartBtn.removeAttr('disabled');
}else{
$(this).parent().find('.stock-alert').remove();
addToCartBtn.removeAttr('disabled');
}
if($(this).val() == '' || isNaN(value)){
$(this).val(0);
}
calculateInputAmt();
})
.on("change", '.components-thumbnail input', function(){
calculateInputAmt();
disableGroupBtns();
});
});
<!-- components.template.html -->
<div class="wrapper-components">
<div class="component selector">
[%ITEM_KITTING id:'[@SKU@]' variation_kitting:1%]
[%PARAM *group_header%]
<input type="hidden" id="model[@rndm@][@SKU@]" name="model" value="[@model@]">
<input type="hidden" id="thumb[@rndm@][@SKU@]" name="thumb" value="[@thumb@]">
<input class="input-tiny btn-large" id="qty[@rndm@][@SKU@]" name="qty" value="[%if [@min_qty@]%][@min_qty@][%else%]1[%/if%]" size="2" type="hidden">
<input type="hidden" id="sku[@rndm@][@SKU@]" name="sku" value="[@SKU@]">
<input type="hidden" id="sku[@rndm@][@SKU@]" name="sku" value="[@QTY@]">
<div class="row wrapper-component-group" data-max="[@assemble_max_qty@]" data-counter="">
<div class="col-xs-12">
<div class="panel panel-default">
[%if [@assemble_group_fullname@]%]
<div class="panel-heading">
<h3 class="panel-title">[@assemble_group_fullname@]
[%if [@assemble_max_qty@]%]
<span class="total-qty hidden"> [%if [@assemble_group_fullname@]%] - [%/if%] Choose [@assemble_max_qty@]</span>
[%/if%]
</h3>
</div>
[%/if%]
<div class="panel-body">
[%/PARAM%]
[%PARAM *body%]
[%if ![@has_variation@]%]
<div class="col-xs-6 col-md-4 wrapper-components-thumbnail">
<input type="checkbox" id="[@sku@]a" class="hidden" checked>
<div class="components-thumbnail thumbnail component[@group_count@]">
<a href="[%asset_url type:'product' id:'[@SKU@]' thumb:'full'%][%END asset_url%]" class=" fancybox" rel="product_images">
<img class="component-var-thumb" component-id="[@component_count@]" src="[%asset_url type:'product' id:'[@SKU@]' thumb:'thumb'%][%/asset_url%]" alt="[@model@]" border="0" id="main-image">
</a>
<div class="caption">
<h4 class="title">[%format type:'text' maxlength:'70' rmhtml:'1'%][@model@][%/FORMAT%]</h4>
<p class="price">
[%IF [@user:group_id@] ne '1'%]
[%if [@itm_price@]%]
[%format type:'currency'%][@itm_price@][%END format%]
[%else%]
[%if [@inpromo@]%]
<strong>Now</strong> [%format type:'currency'%][@promo_price@][%/format%]
[%else%]
[%format type:'currency'%][@store_price@][%/format%]
[%/if%]
[%/if%]
[%ELSE%]
<a href="https://evo.neto.com.au/_myacct/login"><strong><u>Login</u> to see prices</strong></a>
[%/ IF%]
</p>
<div class="input-group">
<input type="number" min="[@min_assemble@]" [%if [@max_assemble@]%]max="[@max_assemble@]"[%/if%] id="productkitting[@rndm@][@kitting_sku@][@component_count@]" [%if [@fixed_assemble@]%]readonly[%/if%] value="[@qty@]" ref="[@sku@]" class="component-config-input form-control [%if [@fixed_assemble@]%]readonly[%/if%]">
</div>
</div>
</div>
</div>
[%else%]
<div class="col-xs-6 col-md-4 wrapper-components-thumbnail">
[%if [@variation_available@] > '0'%]<input type="checkbox" id="[@sku@]a" class="hidden" checked>[%/if%]
<div class="components-thumbnail thumbnail component[@group_count@]">
<a href="[%asset_url type:'product' id:'[@SKU@]' thumb:'full'%][%END asset_url%]" class=" fancybox" rel="product_images">
<img class="component-var-thumb" component-id="[@component_count@]" src="[%asset_url type:'product' id:'[@SKU@]' thumb:'thumb'%][%/asset_url%]" alt="[@model@]" border="0" id="main-image">
</a>
<div class="caption">
<h4 class="title">[%format type:'text' maxlength:'70' rmhtml:'1'%][@model@][%/FORMAT%]</h4>
<p class="price">
[%if [@itm_price@]%]
[%format type:'currency'%][@itm_price@][%END format%]
[%else%]
[%if [@inpromo@]%]
<strong>Now</strong> [%format type:'currency'%][@promo_price@][%/format%]
[%else%]
[%format type:'currency'%][@store_price@][%/format%]
[%/if%]
[%/if%]
</p>
[%if [@variation_available@] < '1'%]
<select disabled class="component-var-opt form-control component-config-input">
<option selected>Out Of Stock</option>
</select>
[%/if%]
[%list_item_variations id:'[@current_sku@]'%]
[%PARAM *variation_header%]
<select class="component-var-opt form-control component-config-input" component-id="[@component_count@]" ref="[@specific_id@]">
<option value="" disabled selected>[@specific_name@]</option>
[%/PARAM%]
[%PARAM *variation_body%]
<option value="[@value_id@]">[@value_name@] [%IF ![@variation_qty@]%](Out of Stock)[%/IF%]</option>
[%/PARAM%]
[%PARAM *variation_footer%]
</select>
[%/PARAM%]
[%/list_item_variations%]
<div class="input-group">
[%if [@variation_available@] > '0'%]
<input type="number" min="[@min_assemble@]" [%if [@max_assemble@]%]max="[@max_assemble@]"[%/if%] id="productkitting[@rndm@][@kitting_sku@][@component_count@]" [%if [@fixed_assemble@]%] readonly [%/if%] value="[@qty@]" ref="[@current_sku@]" component-id="[@component_count@]" component-sku="[@SKU@]" class="component-var-sku form-control component-config-input [%if [@fixed_assemble@]%]readonly[%/if%]">
[%else%]
<input type="number" readonly value="0" class="form-control readonly">
[%/if%]
</div>
</div>
</div>
</div>
[%/if%]
[%/PARAM%]
[%PARAM *group_footer%]
</div>
</div>
</div>
</div>
[%/PARAM%]
[%/ITEM_KITTING%]
</div>
<div class="row">
<div class="col-xs-12 col-md-5">
[%if [@preorder@]%]
<button type="button" title="Add to Cart" class="addtocart btn btn-block btn-warning btn-lg" rel="[@rndm@][@SKU@]"><i class="icon-time icon-white"></i> Pre-Order Now</button>
[%else%]
[%if [@store_quantity@] >= '1'%]
<button type="button" title="Add to Cart" class="addtocart btn btn-success btn-block btn-lg" rel="[@rndm@][@SKU@]"><i class="icon-shopping-cart icon-white"></i> Add to Cart</button>
[%/if%]
[%/if%]
</div>
</div>
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment