I have created a simple AJAX request which feeds back to the header template. However, I can not seem to be able to do any of the following assign, capture, render, include.
<script id="CartPopover" type="text/x-handlebars-template">
{% raw %}
{{#items}}
{% render "cart-item", item: item %}
{{/items}}
{% endraw %}
</div>
Update
I am attempting to update the sliding side cart on the website when a product is added to cart. Please see the ajax, /cart/add.js success
function below.
var showCartNotificationPopup = function (product) {
var addedQuantity = parseInt($('.quantity__input', this.$container).val());
$.get("/cart.json", function (data) {
var cart_items = data.items
$.each(cart_items, function (index, item) {
item.minus_quatinty = item.quantity - 1;
item.formatPrice = Shopify.formatMoney(item.final_price)
})
cart = {
items: data.items
}
$("#side-cart-container").find(".item").detach();
$("#CartOuter table tbody").prepend(template(cart));
console.log(cart);
$("#side-cart-container").addClass("visible");
});
clearTimeout(popoverTimer);
}
You are misunderstanding how Shopify works. Liquid code is parsed once by Shopify when a page is loaded. Shopify creates a huge string of HTML, CSS and JS and dumps it into the browser.
Once you are in the land of Javascript, you no longer play with Liquid. Instead, you play with data. So, if you want to update the cart, you use Javascript. If you want to know what is in the cart, you use Javascript. If you want to re-render the contents of the cart, you replace the DOM you no longer like with new DOM. Use Javascript templates for this.
No amount of Liquid in your JS will help you except during render time. At render time, you can certainly build and fill a Javascript data structure with data from Liquid.
Related
In order to hide a line of text on an empty cart I tried
{% if cart.item_count > 0 %} your html here {% endif %}
This seems to work because it does when the cart starts out empty. But I assume the page is not refreshing during add to cart (That seems to be the case if a theme using ajax add to cart functionality.)
I wonder what I need to do in order to make it work anyway?
Yes, liquid is a server-side rendered language. There is nothing you can do in liquid to update the page after an ajax call.
The only way is Javascript.
When you do the ajax call, your should be calling the cart.js or add.js or update.js endpoints, in these cases you receive an object with an array: items.
You need to check (in Javascript) if responseData.items.length>0 to see if there are items in the cart.
To make an example, this is your .liquid.
{% if cart.item_count > 0 %}
<div id="#mycart">...</div>
{% endif %}
Now in your javascript code, you might have something like
$.ajax({
type: 'POST',
url: '/add.js',
data: payload,
dataType: 'json',
success: function (data) {
if (data["item_count"] === 0) {
$("#mycart").hide();
}else{
$("#mycart").show();
}
},
error: function () {
handleError();
}
});
I'm using jQuery, but is just to give you the idea.
I have a landing page that contains the add to cart button with the product handle like this:
shopifystorename.com/some-product-handle
What I want is to redirect automatically or the product be added automatically to the shopify cart if the user lands on that url above. I've tried using JS:
let m = window.location.href;
var n = m.lastIndexOf('/');
var result = m.substring(n+1);
console.log(result);
var span = document.getElementById("handle");
span.textContent = result;
And capture it on shopify liquid like so:
{% capture my_variable %}<span id="handle">test</span>{% endcapture %}
{{ my_variable }}
{{ all_products[my_variable].title }}
But I'm not getting the value or it is not updated.
It won't work. Liquid is for server-side rendering engine and JS is for frontend. You'll need to purely use Javascript here to make use of AJAX API of Shopify and in a more refined and simple way.
var thisProduct = await fetch('/products/'+ location.pathname +'.js').then(p => { return p.json(); });
alert('The title of this product is ' + thisProduct.title);
So I used shopify liquid to add a collection page, in this collection page, there is multiple products. A button named "Add all" will add all products from this collection to shopping cart when click.
How can I achieve this in shopify liquid language? Or how many way we can do this?
Also, when I tried to use this from the official doc
jQuery.post('/cart/add.js', {
quantity: 1,
id: 10911378372,
properties: {
'First name': 'Caroline'
}
}).done(function() {
console.log("second success");
})
.fail(function(err) {
if(err.statusText !== 'OK'){
console.log("error", err);
}
})
.always(function() {
console.log("finished");
});
even the statusText is Ok, it falls into the fail block and I don't know why.
Well for add multiple items to cart is neccesary a recursive loop.
I did a code for this issue, feel free for use:
github link
the sample is in the begin function:
//IF PROPERTIES IS EMPTY ONLY SET FALSE
MGUtil.data = [
{"id":"12345","qty":2,"properties":{"data1":"1"}},
{"id":"34567","qty":3,"properties":{"data2":"1"}},
{"id":"67892","qty":1,"properties":{"data3":"1"}},
{"id":"23456","qty":6,"properties":false}
]; // ADD 4 ITEMS
MGUtil.total = MGUtil.data.length;
MGUtil.action = 'add';
MGUtil.recursive();//EXECUTE
You would actually do this with a set of AJAX calls. You can only add one item to the cart at a time. See the AJAX API help.
Then you'd use .liquid to get the default variant id for each displayed product either into a list or, what I generally do, as something like:
<div data-variant="{{ product.selected_or_first_available_variant }}">
...
</div>
see: https://help.shopify.com/themes/liquid/objects/product#product-selected_or_first_available_variant to see if that would be sufficient
and then your button script would gather the variant ids and add them one-by-one to the cart.
There is an example here of adding an item to the cart with JQuery
TLDR: has the ajaxsubmit url parameter been renamed in Stencil, or is there a better way to add multiple sizes with different quantities to the cart quickly?
I need to have separate quantity boxes for each size of a product so customers can order for sports teams. I have been able to make this format appear on the frontend by using this code in templates/components/products/set-select.html:
{{#if display_name '==' 'Size'}}
{{#each values}}
<label>{{label}}</label>
<input class="size-quantity" type="tel" name="{{id}}">
{{/each}}
<script>
sizeattributeid = {{id}};
</script>
{{/if}}
I have also created a separate 'Add Sizes to Cart' button that fires a function looping through each .size-quantity box to collect the 'name' and 'val' of each one so I can submit it to the cart.
My first thought was to do this via an ajax request with jQuery like this:
productid = jQuery('input[name="product_id"]').val();
jQuery('.size-quantity').each(function() {
qty_value = jQuery(this).val();
sizeattributevalue = jQuery(this).attr('name');
$.ajax({
type: 'GET',
url: cartUrl+'?action=add&product_id='+productid+'&qty[]=qty_value&attribute['+sizeattributeid+']='+sizeattributevalue+'&ajaxsubmit=1&fastcart=1',
success: function(data) {
//parse bigcommerce html reponse
var obj = JSON.parse($(data).html());
//success property = true if item was added successfully
if (obj.success) {
console.log('yay!');
} else {
console.log('fail!');
}
}
});
});
And I have been able to get the crafted URL to add a product to the cart if I paste the generated url into the browser...but I have not been able to with ajax. It seems the ajaxsubmit part of their code does not work with Stencil the way that it worked with Blueprint.
Has this code been renamed? My only alternative to this has been to hide the select box for size and the box for quantity, and then on submit loop through each size and have the quantity box fill in with the desired quantity and submit the form...but that is slow and the only way I've been able to get that to work is by spacing out my requests 600ms at a time, an unacceptable wait.
I'm trying to hide access from competition viewing the best-sellers, specifically using a URL like this:
www.store.myshopify.com/collections/all?sort_by=best-selling
I've tried {% if collection.url contains 'sort_by=best-selling' %} but that doesn't work. Is there any way to target a URL with an attached query string?
If not, any suggestions?
Thanks!
Unfortunately collection.url doesn't return the query string, in your example, it would output /collections/all
I don't think there's a way in Liquid to get the current url query string. You can only set the default sort type with collection.default_sort_by : 'price'
Or to override all sorting with {% assign products = collection.products | sort: 'price' %}
You can override the sort_by query string parameter using jQuery to substitute best-selling by price:
<script type="text/javascript">
$.urlParam = function(name){
var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
return results[1] || 0;
}
var sort_by = $.urlParam('sort_by');
if(sort_by == "best-selling") {
var url = window.location.href;
url = url.replace("best-selling", "price"); // override to sort by price
window.location.href = url; // redirect to url
}
<script>
Using this code with your example, it would automatically redirect the page www.store.myshopify.com/collections/all?sort_by=best-selling to www.store.myshopify.com/collections/all?sort_by=price
But keep in mind that your competitors could disable that JS code and still access the best-selling items.