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.
Related
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);
I have a custom checkout experience in my Shopify store that I only want to allow if all products in the cart contain the tag "test"
This is the function I currently have, which seems to only work with a single item in the cart.
function productTags() {
{%- assign tagEnabled = false -%}
return {
{%- for item in cart.items -%}
{%- if item.product.tags contains 'test' -%}
"{{ item.product.tags }}": {{ item.quantity | json }}
{%- assign tagEnabled = true -%}
{%- endif -%}
{%- endfor -%}
};
}
this line ( "{{ item.product.tags }}": {{ item.quantity | json }}) is only there for display in the console when testing this. I can remove that if necessary.
How can I expand this to look for all item tags in the cart, and only assign the tagEnabled variable to true if all of them have the same tag?
Thanks in advance!
It looks like you are trying to mix Liquid with Javascript, which can make coding confusing. I would recommend splitting your code into two parts: one where you collect your Liquid variables and assign them to Javascript variables (and I see you are using the json filter to do that already, which is awesome - that filter guarantees that your variable output will be in a Javascript-legal format), and the second part where you write your Javascript code without any Liquid brackets getting in the way. (This is especially helpful if you are using a code editor with any syntax or error highlighting)
Let me know if the following helps you get the information you need:
// The Liquid filter 'map' lets you drill into nested object properties. We can use this to get an array of tag arrays.
// The JSON Liquid filter will turn any Liquid variable into a legal Javascript variable.
const itemProductTags = {{ cart.items | map: 'product'| map: 'tags' | json }}
// Check on our variables
console.log('All product tag arrays', itemProductTags)
console.log('Results of tagCheck()', tagCheck(itemProductTags, 'test') )
function tagCheck(tagsList, targetTag){
// Checks to see if the targetTag appears in all, some or none of the tag arrays.
// tagsList will be an array of arrays
var targetInAny = false;
var targetInAll = true;
for(var i=0; i<tagsList.length; i++){
var tags = tagsList[i];
if(tags.indexOf(targetTag) != -1){
// Found the tag - this targetTag appears in at least one product-tag list
targetInAny = true;
}
else{
// Did not find the tag - this targetTag is NOT in every product-tag list
targetInAll = false;
}
}
// Returns an object specifying if we found the target in any, all or none of the lists
return { targetInAny: targetInAny, targetInAll: targetInAll, targetInNone: !targetInAny }
}
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.
In my online shop I want to show some more data about each product. I have managed to do this by adding an extra nodes to settings_data.json file. Like this:
{
"current": {
...
...
"7887193478": { //Product ID
"has-badge" => true,
"show-image" => false
...
},
"7887193479": { //Product ID
"has-badge" => true,
"show-image" => true
...
},
}
}
It is working and I am getting the data and showing it successfully.
The good thing about this solution is the page load is very fast.
But the problem is when some one updates the theme setting it overrides the settings_data.json file. Is there any way that I can import this extra json settings separably into my Shopify?
Please do not advise me with Metadata App. Metadata app is very slow and I am not interested to use it.
You can create a snippet products_data.liquid (or any other name you want) that stores the information you need, that's separate from the theme settings file, and won't be overwritten. Here's an example:
{% assign "7887193478-has-badge" = true %}
{% assign "7887193478-show-image" = false %}
{% assign "7887193479-has-badge" = true %}
{% assign "7887193479-show-image" = true %}
...
Then you'll want to include it somewhere in there theme.liquid file, above where you'd be using it:
{% include "products_data" %}
The downside is that it's not as clean in terms of data entry.
Right now it seems variables I create can't communicate across files.
For Liquid you can pass a variable in the include
{%- assign global_var = "VALUE" -%}
{%- include 'YOUR_FILE' global_var: global_var -%}
For Shopify liquid you can do the following:
There is a work around this, you can set the global variable in the theme settings as an option config/settings_schema.json
{
"type": "text",
"id": "global_variable",
"label": "global variable",
"default": "Variable value"
},
and you can access it in the liquid files through
settings.global_variable
But the value is depending on what you enter in the theme settings.
If you need more dynamic way, you can set cart attributes through ajax like:
$.ajax({
type: 'POST',
url: '/cart/update.js',
data: { attributes: {'global_variable': "MY_VALUE"} },
dataType: 'json',
success: function(cart) {
location.reload();
}
});
And then access it any where in the theme through
cart.attributes.global_variable
But you have to update it each time the cart is empty
It seems the templates are loaded before the theme, so variables set in your layout/theme file wont be present in templates. Frustrating. However you can set them via a snippet, and include this snippet in your templates, layout, etc
In Liquid, as you want for example to determine the language and reuse this code in multiple occasions, you can create an file in the render folder.
instead of calling this using render, use include. Then it returns the assigned value. For example, create "render/current_language.liquid" :
{%- liquid
assign current_language = 'en'
if request.path contains '/nl/'
assign current_language = 'nl'
endif
%}
In a other file you can use as follows:
{%- liquid
include 'get-language'
if current_language == 'en'
else
endif
%}
As long as you use the
{% assign variable = value %}
you should be able to get the value anywhere in the file, and any file included after it has been assigned.
I believe this is the closest you can get to global variables in it.