Shopify cart page - Changing quantity input value with jQuery - shopify

I have + and - buttons in the cart layout that are changing the value of the quantity input using jQuery.
It works perfectly on the page and in the source code (quantity values changes) but it doesn't work after page refresh and doesn't get reflected on the checkout page.
Changing the quantity manually (with built-in input arrows or by typing the new amount into the field) works normally.
$(".qty-button").on("click", function() {
var $button = $(this);
var oldValue = $button.parent().find("input").val();
var newVal;
if ($button.text() === "+") {
newVal = parseFloat(oldValue) + 1;
} else {
if (oldValue > 0) {
newVal = parseFloat(oldValue) - 1;
} else {
newVal = 0;
}
}
$button.parent().find("input").attr('value', newVal).trigger('change');
});
It changes the value in the page source and is reflected on the cart page but does nothing in terms of functionality as it gets back to the original value on page refresh or checkout.
Any ideas?

Didn't know I need to fire the Shopify Cart API.
In case anyone needs it in the future, fixed with:
<div class="cart-item-block qty-selector">
<div class="qty-button increase" onclick="Shopify.addItem({{ item.variant.id }}, this.parentNode.querySelector('input[type=number]').value)">+</div>
<input id="updates_{{ item.key }}" class="cart-qty-input" type="number"
name="updates[]" value="{{ item.quantity }}" min="1" pattern="[0-9]*"
>
<div class="qty-button decrease" onclick="Shopify.removeItem({{ item.variant.id }}, this.parentNode.querySelector('input[type=number]').value)">-</div>
</div>
<script>
Shopify.addItem = async function(id,quantity){
await $.ajax({
method:'POST',
url:'/cart/change.js',
data:{ id:id, quantity:(++quantity) },
dataType: 'json'
})
};
Shopify.removeItem = async function(id,quantity){
await $.ajax({
method:'POST',
url:'/cart/change.js',
data:{ id:id, quantity:(--quantity) },
dataType: 'json'
})
};
</script>

Related

Why watcher does not run?

I have the following data property called selector, which I set its initial value in mounted() since it is an HTML element that also has a bit of delay due to loading I set its value in a setTimeout(). Then whenever I select a different option its value should obviously change. And this change should we watched. Right now the watcher does not seem to work and I can't see why. Can someone help?
My data propery:
data() {
return {
selector: " ",
}}
my watcher:
watch: {
// whenever selector changes, this function will run
selector: function(newSelection) {
console.log("in watcher", newSelection);
$(".page-item a").each(function() {
if ($(this).text() == ">") $(this).text(" ");
else if ($(this).text() == ">>") $(this).text(" ");
else if ($(this).text() == "<") $(this).text(" ");
else if ($(this).text() == "<<") $(this).text(" ");
});
}
},
and mounted()
mounted() {
setTimeout(function() {
document
.getElementsByTagName("select")[0]
.setAttribute("id", "VueTables__limit");
this.selector = document.getElementById("VueTables__limit").value;
console.log("in mounted", this.selector);
}, 2000);
}
HTML:
<div class="form-group form-inline pull-right VueTables__limit">
<div class="VueTables__limit-field">
<label for="VueTables__limit" class="">Records:</label>
<select name="limit" id="VueTables__limit" class="form-control">
<option value="10">10</option>
<option value="25">25</option>
<option value="50">50</option></select></div></div>
Update your mouted function:
mounted() {
var self = this; //save the ref of 'this'
setTimeout(function() {
document
.getElementsByTagName("select")[0]
.setAttribute("id", "VueTables__limit");
self.selector = document.getElementById("VueTables__limit").value;
console.log("in mounted", this.selector);
}, 2000);
}
First of all, if you need to setup initial data value and call some methods during component's lifecycle, use watcher with immediate: true. Next, default value could be just empty string "" no need to add space. And the last, why you use jQuery, when you have vue? Don't get it

Vue selectize, getting json data from option?

I'm using vue2-selectize to display list of options fetched from axios call:
<template>
<selectize v-model="selected" :settings="settings">
<option v-for="option in options" :value="option.id">
({{ option.author }}) - {{ option.description }}
</option>
</selectize>
</template>
<script>
export default {
props: ['old-value'],
data() {
return {
selected: this.oldValue,
options: [],
settings: {
preload: true,
placeholder: "Search All Authors",
dropdownParent: 'body',
closeOnSelect: true,
render: {
option: function (data) {
console.log(data);
return '<div>' +
data.displayName +
'<div class="item-bio">' +
data.bio +
'</div>';
}
},
load: async (query, callback) => {
axios.get(route('api.showAllAuthors')).then(response => {
this.options = response.data;
callback();
})
}
},
}
},
}
</script>
The issue is that once you setup the <option> for the select you can only work with the two values it passes to the render function (text and value) and not the original object (whereas the actual <option> has access to this object).
The manual mentions the optional parameter of dataAttr available for <option> tags, but setting <option :data-data="option"> has no effect and I still can't access the original properties.
How can I access the original JSON attributes that the <option> is using in the render function?
var value = selectizeObject.getValue(),
optionJson = selectizeObject.options[value];
selectizeObject is object for given select / input. For example with jQuery:
var selectizeObject = $('#my-select')[0].selectize;

Updating vue js value

I want to update a placeholder (currentUsername) asynchronously with an actual value after loading/rendering the page.
I tried following a sample project (https://github.com/jackfranklin/vue2-demo-proj), but I can't correlate it with my setup. Using vuejs 2.0.
I can see the event is triggered, the call is made and something's returned, I've got no errors on my Chrome console, but nothing is updated in the UI. Why is that?
1) html file:
<script src="assets/js/data.js"></script>
2) data.js:
"use strict";
import * as DataXXX from './data.vue';
Vue.component("dataxxx", DataXXX);
var vm = new Vue({
el: "#app",
});
3) data.vue
<template>
<div>
<p v-if="currentUsername == null">
Null username
</p>
<p v-else>
Username: {{ currentUsername }}:
</p>
</div>
</template>
<script>
"use strict";
export default
{
created()
{
awr.EventsBus.$on("requestLoadData", this.loadData);
awr.EventsBus.$emit("requestLoadData", this.loadData);
},
destroyed()
{
awr.EventsBus.$off("requestLoadData", this.loadData);
},
methods:
{
loadData(name)
{
alert("got event");
this.currentUsername = name;
this.fetchGithubData(name);
},
fetchGithubData(name)
{
const url = "http://127.0.0.1/getUsername.php";
alert("requesting url: " + url);
fetch(url).then(response => response.text()).then(data => {
this.currentUsername = data;
console.log("got response: " + data);
});
}
},
data() {
return {
currentUsername: null
}
}
}
</script>
The if isn't re-evaluated when you get the response, so the placeholder isn't included in the page.
This line DOES update it, but it's just not shown: this.currentUsername = data;
Change it to something like:
<div>
Username: {{ currentUsername }}
</div

how to count review per product and show in product listing in big commerce?

Please find attached image which is gives you idea
i want to count review per product
Please find attache code
<li class="%%GLOBAL_AlternateClass%%">
<div class="inner">
<div class="ProductImage QuickView" data-product="%%GLOBAL_ProductId%%">
%%GLOBAL_ProductThumb%%
</div>
<div class="ProductDetails">
%%GLOBAL_ProductName%%
</div>
<em class="p-price">%%GLOBAL_ProductPrice%%</em>
<div class="ProductPriceRating">
<span class="Rating Rating%%GLOBAL_ProductRating%%">
<img src="%%GLOBAL_IMG_PATH%%/IcoRating%%GLOBAL_ProductRating%%.png" alt="" style="%%GLOBAL_HideProductRating%%"/>
</span>
</div>
<div>
<div class="ProductCompareButton" style="display:%%GLOBAL_HideCompareItems%%">
<input type="checkbox" class="CheckBox" name="compare_product_ids" id="compare_%%GLOBAL_ProductId%%" value="%%GLOBAL_ProductId%%" onclick="product_comparison_box_changed(this.checked)"/> <label for="compare_%%GLOBAL_ProductId%%">%%LNG_Compare%%</label> <br>
</div>
<div class="ProductActionAdd" style="display:%%GLOBAL_HideActionAdd%%;">
%%GLOBAL_ProductAddText%%
</div>
</div>
</li>
This jQuery snippet can be inserted on the category page to asynchronously access each product, and determine the number of reviews on the page.
// For each product on the category page...
$('.ProductDetails').each(function(index) {
var $self = $(this); // Make local reference to 'this'.
// Parse the URL from the individual product, and retrieve its Reviews Count:
getProductPageReviewCount($self.find('>:first-child').attr('href')).then(function(count) {
// Insert the number of reviews below the Product Name:
$self.find('>:first-child').after("<a>" +count +" Reviews</a>");
}).catch(function(err) {
// Catch any Ajax Errors:
console.log('Error - ', err);
});
});
/**
* Determines the total number of reviews for a particular
* external product page, according to its URL.
* #param url <string> - The product page's URL.
* #return Promise\<int> - The number of reviews on the page, or error on failed request.
*/
function getProductPageReviewCount(url) {
return new Promise(function(fulfill, reject) {
$.ajax({
method: 'GET',
url: url,
success: function(res) {
fulfill($(res).find('.ProductReviewList > li').length);
},
error: function(err) {
reject(err);
}
});
});
}
$(document).ready(function(){
$('.ProductList').each(function(){
$(this).find('li').each(function(){
var current = $(this);
var mainURL = window.location.href;
var productUrl = current.find('div div a').attr('href');
if(mainURL.indexOf('https')!==-1){
productUrl = current.find('div div a').attr('href').replace('http','https');
}
$.ajax({
url: productUrl,
type: "POST",
dataType: "html",
success: function (data) {
var ht = $(data);
var review = ht.find('#productTotalReview').text();
current.find('div span').append("<br>&nbsp"+review);//.replace('product reviews','Reviews'));
}
});
});
});
});

Vue js http request loop

I'm trying to create a live search form which is calling a http request whenever there is user input. So far the live searching works well, but the http request results in a loop. This problem shows up when I'm assigning the catalog_items to this.items.
Vue.js
Vue.filter('searchFor', function (value, searchString) {
var result = [];
if(!searchString || searchString.length < 2){
return value;
}
searchString = searchString.trim().toLowerCase();
this.fetchData(searchString);
result = this.items;
return result;
})
new Vue({
el: '#searchform',
data: {
searchString: "",
items: []
},
methods: {
fetchData: function (name) {
this.$http.get('api_url' + name )
.then(function(response){
var data = response.data;
var catalog_items = data['catalog_items'];
this.items = catalog_items;
})
}
}
})
The html search input:
<input type="text" v-model="searchString" placeholder="Enter your search terms" />
<ul>
<li v-for="item in catalog_items | searchFor searchString">
<p>#{{item.name}}</p>
</li>
</ul>
Thanks in advance!