Passing data attributes from Shopify Schema blocks to JS - javascript

I'd like to pass data from the following schema setting to JS. Multi-word strings will be input in the editor. Using a slick slider, the user should be able to click through the quotes and see the current quote. However, when the quotes show up, only the first word of the string is displayed. For example: if the string "New York Times" is entered in the editor, only "New" is displayed". How can I fix my code so that the whole string is passed to JS?
In the liquid file I have the following:
<li class="press-slider-item" data-quote={{block.settings.quote}} {{ block.shopify_attributes }}>
...
{
"type": "textarea",
"id": "quote",
"label": "Featured Quote"
}
I attempted to access the data values by doing the following in JS:
var quoteList = [];
$(document).ready(()=>{
const slides = document.querySelectorAll('.press-slider-item');
slides.forEach(slide=>quoteList.push(slide.dataset.quote));
...
Then the Slick afterChange event is defined:
$('.press-slider').on('afterChange', function(event, slick, currentSlide, nextSlide){
const featQuote = document.getElementById('press-featured-quote');
if(currentSlide + 1 == quoteList.length){
console.log(quoteList[0]);
featQuote.innerHTML = quoteList[0];
}else{
console.log(quoteList[currentSlide+1]);
featQuote.innerHTML = quoteList[currentSlide+1];
}
});

I figured it out using inline scripts. Here's my solution. Not sure if this is the best way to do this, but it works for what I need.
<script>var quoteList = [];</script>
<ul class="press-slider">
{% for block in section.blocks %}
<li class="press-slider-item"{{ block.shopify_attributes }}>
<script>quoteList.push(`{{block.settings.quote}}`)</script>
{% if block.settings.link != blank %}
<a href="{{ block.settings.link }}" class="logo-bar__link">
{% endif %}
{% if block.settings.image != blank %}
{{ block.settings.image | img_url: '160x160', scale: 2 | img_tag: block.settings.image.alt, 'logo-bar__image' }}
{% else %}
{{ 'logo' | placeholder_svg_tag: 'placeholder-svg' }}
{% endif %}
{% if block.settings.link != blank %}
</a>
{% endif %}
</li>
{% endfor %}
</ul>
<script>
$('.press-slider').on('afterChange', function(event, slick, currentSlide, nextSlide){
const mediaQuery = window.matchMedia('(min-width: 481px)');
// Check if the media query is true
if (mediaQuery.matches) {
const featQuote = document.getElementById('press-featured-quote');
if(currentSlide + 1 == quoteList.length){
featQuote.innerHTML = quoteList[0];
}else{
featQuote.innerHTML = quoteList[currentSlide+1];
}
}
});
</script>

Related

Shopify get meta field value of product using JS/jQuery

I've been exploring and testing for hours how to retrieve the metafield values from a specific product handle.
I've tested using AJAX calls and using getJSON neither of which have had any success with all seem to throw the same error.
I'm aware that you most definitely can't access the product metafields directly as they're somewhat protected and therefore are excluded from the usual handle.js file I'm currently successfully able to get.
I am seeking someones help to essentially point me in the direction of how to accomplish what I'm looking for.
product-view.js file
$(document).ready(function () {
$.getScript("//cdnjs.cloudflare.com/ajax/libs/fancybox/2.1.5/jquery.fancybox.min.js").done(function() {
createProductData();
});
});
function createProductData() {
$(".product-view").click(function () {
if ($('#product-view').length == 0){
$("body").append('<div id="product-view"></div>');
}
var product_handle = $(this).data('handle');
$('#product-view').addClass(product_handle);
//Default Product Fields
jQuery.getJSON('/products/' + product_handle + '.js', function (product) {
var images = product.images;
var title = product.title;
var price = product.price;
var desc = product.description;
});
//Product Meta Fields
jQuery.getJSON('/products/' + product_handle + '?view=metafields.json', function (product) {
var dish_type = product.metafields.arena.dish;
console.log(dish_type);
//error: Cannot read properties of undefined (reading 'arena')
});
});
}
product.metafields.liquid file
{% layout none %}
{{ product.metafields.arena | json }}
So I managed to find a website finally that used what they described as a 'hack' because they don't believe this is the way that {% capture %} however, it did achieve the require outcome that I needed and hopefully is useful for others in future:
theme.liquid file
{% capture 'dishMetaFields' %}
{
{% for product in collections["all-dishes"].products %}
"{{ product.handle }}" : {
product_chinese_title : "{{product.metafields.arena.chinese_title}}",
product_feeds : "{{product.metafields.arena.feeds}}",
product_spice_level : "{{product.metafields.arena.spice}}",
product_dish : "{{product.metafields.arena.dish}}",
product_proteins : "{{product.metafields.arena._proteins}}",
product_diet : "{{product.metafields.arena._diet}}",
product_cooking_time : "{{product.metafields.arena._diet}}",
product_cooking_video : "{{product.metafields.arena._method_video}}",
product_cooking_text : "{{product.metafields.arena._method}}",
product_nutrients : "{{product.metafields.arena._nutrition}}",
product_allergies : "{{product.metafields.arena._allergies}}",
{% unless product.metafields.arena._bundle_dishes == blank %}
{%- assign dishCounter = 1 -%}
product_bundle_dish : {
{% for value in product.metafields.arena._bundle_dishes %}
"dish-{{ dishCounter }}" : "{{ value }}",
{%- assign dishCounter = dishCounter | plus:1 -%}
{% endfor %}
}
{% endunless %}
},
{% endfor %}
}
{% endcapture %}
<script type = "text/javascript">
let dishMetaFields = {{ dishMetaFields }}
</script>
You can then access the dishMetaFields from the javascript file you're using to access the product object to get the defined metafields should the handles match.
product-view.js
$(document).ready(function () {
$.getScript("//cdnjs.cloudflare.com/ajax/libs/fancybox/2.1.5/jquery.fancybox.min.js").done(function() {
createProductData();
});
});
function createProductData() {
$(".product-view").click(function () {
if ($('#product-view').length == 0){
$("body").append('<div id="product-view"></div>');
}
var product_handle = $(this).data('handle');
$('#product-view').addClass(product_handle);
jQuery.getJSON('/products/' + product_handle + '.js', function (product) {
//Default Product Fields
var images = product.images;
var title = product.title;
var price = product.price;
var desc = product.description;
//Product Meta Fields
var metafields = dishMetaFields[product_handle];
var dish_type = metafields.product_dish;
});
});
}
You can also do it like this following your initial approach. In this scenario, you don't need to iterate over all metafields of a collection but only for the required product. This should be better comparatively in terms of performance. The idea is same, that you generate the JSON object in Liquid snippet and then parse the JSON in JavaScript.
{% layout none %}
{
"product_chinese_title" : "{{product.metafields.arena.chinese_title}}",
"product_feeds" : "{{product.metafields.arena.feeds}}",
"product_spice_level" : "{{product.metafields.arena.spice}}",
"product_dish" : "{{product.metafields.arena.dish}}",
"product_proteins" : "{{product.metafields.arena._proteins}}",
"product_diet" : "{{product.metafields.arena._diet}}",
"product_cooking_time" : "{{product.metafields.arena._diet}}",
"product_cooking_video" : "{{product.metafields.arena._method_video}}",
"product_cooking_text" : "{{product.metafields.arena._method}}",
"product_nutrients" : "{{product.metafields.arena._nutrition}}",
"product_allergies" : "{{product.metafields.arena._allergies}}"
{% unless product.metafields.arena._bundle_dishes == blank %}
,
{%- assign dishCounter = 1 -%}
"product_bundle_dish" : {
{% for value in product.metafields.arena._bundle_dishes %}
"dish-{{ dishCounter }}" : "{{ value }}"
{% if forloop.last == false %}
,
{% endif %}
{%- assign dishCounter = dishCounter | plus:1 -%}
{% endfor %}
}
{% endunless %}
}
And for JavaScript part, use simple GET and then parse the response.
jQuery.get('/products/' + product_handle + '?view=metafield', function (product) {
console.log(product)
console.log(JSON.parse(product))
});

'first_time_accessed' Shopify liquid variable is always false

I'm trying to use the first_time_accessed liquid variable in my checkout.liquid Shopify template to decide whether or not to push certain data to an array, like so:
config.elements.push({
id: prodId,
price: prodPrice,
quantity: prodQty,
{% if first_time_accessed %}
{% assign last_purchase_date = "January 1, 1970" %}
{% for order in customer.orders %}
{% if (order.order_number != checkout.order.order_number) and (order.created_at > last_purchase_date) %}
{% assign last_purchase_date = order.created_at %}
{% endif %}
{% endfor %}
{% assign raw_new_customer_boundary = 'now' | date: "%s" | minus : 46656000 /* 540 days */ %}
{% assign raw_last_purchase_date = last_purchase_date | date: "%s" | minus: 0 %}
new_customer: {% if raw_new_customer_boundary > raw_last_purchase_date %}true{% else %}false{% endif %},
{% endif %}
});
However, every time I test this code I can see that first_time_accessed is always false. I've also tested this by putting similar code on other pages and it always equates to false. I've tested it in incognito mode with a VPN and same thing.
I'm wondering if anyone has any idea why first_time_accessed is always false? I'm sure it has to do with some misunderstanding on my end about how this variable works, but there's very little info on Shopify's docs about it.

building a array/object in a nunjucks loops

I have the following in my nunjucks file,
{% set inProgressJobs = [] %}
{% for job in jobs %}
{% set inProgressJobs = (setProgressJobs.push([
{
text: "<b>{{ job.jobTitle}}</b>"
}
]), inProgressJobs) %}
When I use this in by view I would expect to see Web Designer but I am actually seeing {{ job.jobTitle }} how I interprolate my var into the text attribute?
You try to coding inside a template. It's a possible (see below) but out of template ideology. Try to put necessary logic to filters and global functions.
const nunjucks = require('nunjucks');
const env = nunjucks.configure();
env.addFilter('print', console.log); // for debug
const html = env.renderString(`
{% set arr = [] %}
{% for i in range(1, 10) %}
{{ '' if arr.push(i) }} {# arr.push always returns non-zero so result will be '' #}
{% endfor %}
{{ arr | print }} {# print arr to console #}
`);
// console.log(html); // html is a pack of spaces and tabs

How do i create and use variables in django

New to Django and its templates.
I'm trying to set a variable given a specific situation, and that part I think ill be able to do, the code below isn't the exact conditions its just there as a demo. The part im stuck on is how do i create a variable name, and then use that name variable elsewhere. Such as within a div or within a method or anywhere else within the html file, and withing different <Script> tags to run methods and for really any purpose.
demo scenario :
{% for row in table.rows %}
{% if row == 2 %}
{% var name = row.name %}
{% endif %}
{% endfor %}
{% if name %}
<div>{{name}}</div>
{% endif %}
my actual code Im trying to implement:
<script type="text/javascript">
function map_init_basic(map, options) {
var markerClusters = L.markerClusterGroup({ chunkedLoading: true });
{% for row in table.rows %}
var x = "{{ row.cells.x }}"
var y = {{ row.cells.y }}
var m = L.marker([y, x])
m.bindPopup("{{row.cells.first_name}} {{row.cells.last_name}} <br>{{row.cells.chgd_add}}");
m.on("click" , ()=>{
//console.log(`${first_name} ${last_name}`)
{% var first_name = {{row.cells.first_name}} %}
})
//changed row.cells.chgd_add to row.cells.Chgd_add to make sure its matching the table
markerClusters.addLayer(m);
{% endfor %}
markerClusters.addTo(map);
}
{% if first_name %}
console.log("{{first_name}}");
{% endif %}
</script>
Django templates are intended to render html but you are trying to render javascript. It can work but the way you are trying to do it is not a good practice; very soon you won't be able to maintain your code.
If you want to pass data directly from python/django to javascript, an accceptable way to do so is to put the data in a dictionary, translate it to a json string and have it set to a var in your javascript.
in a view:
data = dumps(some_dictionary)
return render(request, 'main/template.html', {'data': data})
in the template:
<script>
var data = JSON.parse("{{data|escapejs}}");
</script>
https://docs.djangoproject.com/fr/3.1/ref/templates/builtins/#escapejs
Alternative: You can use django to generate a widget with data attributes and have a javascript operating on this widget and do whaterever needs to be done.

How to add third level of category menu in dotLiquid

I am working in Comarch E-sklep program made by Comarch where I am using dotLiquid language to modify shop template. I need help to show 3rd level of categories. Standard dotLiquid script allows you to get only two levels of menu. In documentation I read that I need to input special javascript code but I don't know how to put it corectly. Because I already started to learn js and don't understand all things.
<h2>Menu</h2>
{% assign groupNodes = page.GroupNodes %}
<ul>
{% for menuTreeOne in groupNodes -%}
<li>{{ menuTreeOne.Name }}
{% if menuTreeOne.Nodes -%}
<span style="color: lightblue;"> yes </span><br>
<ul>
{% for menuTreeTwo in menuTreeOne.Nodes -%}
<li>{{ menuTreeTwo.Name }}</li>
{% endfor -%}
</ul>
{% else %}
<span style="color: red;"> nope </span>
{% endif -%}
</li>
{% endfor -%}
</ul>
Fragment from documentation:
Action GET
This action allows you to download data from the server to create, for
example: breadcrumbs or menu.
Get/Groups
Gets the subgroups for the specified group. This action allows you to
build a dynamic menu or breadcrumbs.
<script type="text/javascript">
(function () {
$(function () {
$('nav.breadcrumbs>ol>li').hover(
function () {
var t = $(this), gId = ('' + t.data('id')).split(',')[1];
if (gId && t.find('ol').length == 0) {
$.get(null, { __action: 'Get/Groups', groupId: gId, languageId: __lngId }, function (d) {
var obj = d.action.Object;
if (obj.length) {
var ol = $('<ol></ol>');
t.append(ol);
$.each(obj, function (i, el) {
var a = $('<a></a>').attr('href', el.Url).text(el.Title);
ol.append(a);
a.wrap('<li></li>')
});
}
});
}
else t.find('ol').show();
},
function () {
$(this).find('ol').hide();
}
);
});
})(jQuery);
</script>

Categories

Resources