Using javascript variables in Shopify liquid - javascript

I am trying to use a javascript variable inside the image tag but it is not working.
I want to create a filter for my collection in a developing project, where I can filter products by the textures of products. I have coded the following:
<div class="collection-filter-navbar-nav">
{% assign tags = 'white, yellow, golden' | split: ',' %}
<ul class="fabric-filter">
<li><a href="javascript:void(0);" >All</a></li>
{% for t in tags %}
{% assign tag = t | strip %}
{% if current_tags contains tag %}
<li><a href="javascript:void(0);" data-value="{{ tag | handle }}" >{{ tag }}</a></li>
{% elsif collection.all_tags contains tag %}
<li>{{ tag }}</li>
{% endif %}
{% endfor %}
</ul>
</div>
The html is showing in the front end, but what I need, I want to add a texture image in each tag in reference to the tag name.
So I scripted :
jQuery(document).ready(function(){
var filter_tabs = jQuery('.fabric-filter > li > a.filter-lists');
jQuery.each( filter_tabs, function(index, element){
var data_value = jQuery(this).data('value');
{% assign value = data_value %}
var img_append = '<img src="{{ 'f1-'+value+'.png' | asset_url }}">'
jQuery(img_append).appendTo(jQuery(this));
console.log(data_value);
});
});
But it is showing error. I know this can be done by css, but I am using javascript just for dynamism.

You won't be able to do this as the liquid code all runs before the jquery code.
By the time you are running the jquery liquid has already outputted the line {% assign value = data_value %}

Related

How to list tags for the current post - Eleventy js?

I am using Eleventy JS. And I can't list the tags for the current post. There is nothing written about this in the official documentation.
All tags are listed easily. But for the current post I can not display the tags on the screen
This code to list all tags in Eleventy JS config file
// Display tag list on page
eleventyConfig.addCollection('tagsList', function (collectionApi) {
const tagsList = new Set()
collectionApi.getAll().map((item) => {
if (item.data.tags) {
// handle pages that don't have tags
item.data.tags.filter((tag) => !['posts'].includes(tag)).map((tag) => tagsList.add(tag))
}
})
return tagsList
})
This loop of outputting tags in the template
---
permalink: /blog/category/
pagination:
data: collections
size: 77
---
<h1>Tags</h1>
<ul>
{% for tag in collections.tagsList %}
{{tag}}
{% endfor %}
</ul>
I use Nunjucks
Displaying tags for the current post with filter:
{% for tag in tags -%}
{% if tag !== 'posts' %}
<a class="tag" href="/blog/category/{{ tag }}">{{ tag }}</a>
{% endif %}
{%- endfor %}

Assign javascript function output to liquid variable

I'm trying to validate an image URL if it exists in javascript. So I add this code in javascript which accepts a URL and returns the http status code.
function imageExists(image_url){
var http = new XMLHttpRequest();
http.open('HEAD', image_url, false);
http.send();
return http.status != 404;
}
And in the liquid template, I want to check the image URL if it exists before displaying kinda like this
<div class="variant-cat-attributes">
{% assign tags = product.metafields.product_meta.tag | split: "," %}
{% for tag in tags %}
<div class="item">
{% capture tag_slug %}{{ tag | replace: " ", "_"}}{% endcapture %}
{% assign img_png = 'tag' | append: '-' | append: tag_slug | append: '.png'%}
{% capture png_exists %}<script>imageExists({{ img_png }})</script>{% endcapture %}
{% if png_exists%}
<img src="{{ img_png | file_img_url: '32x32' }}" />
{% else %}
{% assign img_jpg = 'tag' | append: '-' | append: tag_slug | append: '.jpg'%}
{% capture jpg_exists %}<script>imageExists({{ img_jpg }})</script>{% endcapture %}
{% if jpg_exists%}
<img src="{{ img_png | file_img_url: '32x32' }}" />
{% else %}
{% assign img_default = 'tag' | append: '-' | append: 'default' | append: '.png'%}
<img src="{{ img_default | file_img_url: '32x32' }}" />
{% endif %}
{% endif %}
<p class="item-name">{{ tag | capitalize }}</p></div>
{% endfor %}
</div>
I'm just starting to understand liquid so I don't know if its correct this way. But what happens with this code is the script tag is taken up as a string and the code in it is not run
png_exists = imageExists({{ img_png }})
How do I solve this?
You are mix matching JS with Liquid, which is OK if you only pass liquid content.
At the moment liquid see your code like so:
{% capture png_exists %}<script>imageExists({{ img_png }})</script>{% endcapture %}
png_exists => <script>imageExists(http://asset_img_url.jpg)</script>
You can't execute Javascript code and expect liquid to know about it, Javascript is executed AFTER liquid, so liquid finish it's logic and Javascript will run it's code afterwards.
So you you can't use javascript functionality in liquid.

Create an iterative counter in DJango template

I've checked a lot of other questions and I haven't seen my particular scenario really addressed and I've tried a lot of things out without success.
What I have is a DJango for loop in my HTML code, and within the for loop is an if statement checking if each element from the list that is being looped through equals a certain value. If that is true, then an entry is created on the page. I need to dynamically print the element number (eg. entry 1 would display as 1. and entry 2 would display as 2.)
The two best attempts I have made are:
1.
<!-- this approach prints out 1 for each entry -->
{% with counter=0 %}
{% for q in questionnaire.questions %}
{% if q.answer %}
<div class="row"><h3>
{{ counter|add:1 }}. {{ q.name }}
</h3></div>
<!-- some other code-->
{% endif %}
{% endfor %}
{% endwith %}
{% for q in questionnaire.questions %}
{% if q.answer %}
<div class="row"><h3>
<span id="displayCount">0</span>. {{ q.name }}
</h3></div>
<!-- some other code-->
{% endif %}
{% endfor %}
<script type="text/javascript">
var count = 0;
var display = document.getElementById("displayCount");
count++;
display.innerHTML = count;
</script>
Any help would be appreciated
You can access the built-in counter of your for loop using forloop.counter. It starts at 1, you can also you forloop.counter0 if you'd like to start at zero.
{% for q in questionnaire.questions %}
{% if q.answer %}
<div class="row">
<h3>
{{ forloop.counter }}. {{ q.name }}
</h3>
</div>
<!-- some other code-->
{% endif %}
{% endfor %}
Filter your queryset in your view as to avoid issues with indexing and separating presentation from logic.

OctoberCMS Javascript API AJAX call to a component function to update component's partial

So I have the following file structure:
plugins/myname/pluginname/components/pluginname/default.htm
plugins/myname/pluginname/components/PluginName.php
default.htm acts as the partial of the component.
and I have the following JS API
setInterval(function(){
$.request('onEverySecond', {
update: {'#default.htm':'#rate-marquee'},
complete: function() {
console.log('Finished!');
}
})
}, 1000);
onEverySecond is a function in PluginName.php that updates a variable called fx thrown to default.htm.
At the front end the partial default.htm seems to be updated, but it refreshes the whole partial which is not what I want, it causes the marquee to replay again and again and only be able to show the first few piece of contents.
All I wanted is that the AJAX will update only the variable fx where the data is updated.
How can I achieve that?
EDIT 1:
Here is the partial markup:
{% set fx = __SELF__.fx %}
<marquee id="rate-marquee" name="rate-marquee" onmouseover="this.stop();" onmouseout="this.start();">
<ul>
{% for item in fx %}
<li>
{{ item.Item | trim('u')}}: {{ item.BID }} {% if item.Revalue == 0 %} <div class="arrow-up"></div> {% else %} <div class="arrow-down"></div> {% endif %}
</li>
{% endfor %}
</ul>
</marquee>
Additionally, here is the code in PluginName.php
public function onRun()
{
$this->addJs('/plugins/SoyeggWebDevelopment/fxmarquee/assets/js/default.js');
$this->updateFX();
}
public function onEverySecond()
{
$this->updateFX();
}
public $fx;
So updateFX() works perfectly well too.
Here problem seems you are replacing whole marquee it causes to re-render it.
To solve this we can just update portion inside marquee
setInterval(function(){
$.request('onEverySecond', {
complete: function() {
console.log('Finished!');
}
})
}, 1000);
We don't do anything special here just a simple ajax call
to update portion of marquee we need to assign id to it and we define internal partial
<marquee id="rate-marquee"
name="rate-marquee"
onmouseover="this.stop();" onmouseout="this.start();">
<ul id='rate-marquee-inner'> <!-- <= here -->
{% partial __SELF__ ~ '::_marquee_inner' %}
</ul>
</marquee>
_marquee_inner.htm partila markup
{% set fx = __SELF__.fx %}
{% for item in fx %}
<li>
{{ item.Item | trim('u')}}: {{ item.BID }} {% if item.Revalue == 0 %} <div class="arrow-up"></div> {% else %} <div class="arrow-down"></div> {% endif %}
</li>
{% endfor %}
and to update that portion we just need to return markup array
function onEverySecond() {
$this->updateFX();
return ['#rate-marquee-inner' => $this->renderPartial('_marquee_inner.htm')];
}
this will just push new updated markup to given id #rate-marquee-inner so now it will just update inner portion of marquee and marquee will not re-render.
if any doubt please comment.

Django: Jquery click function not working in Ajax

I have been working through the Tango with Django exercises to cut my teeth into Django. Almost done but having a problem with the Ajax part.
Ajax function to auto_add a page is not being called. Idk what the problem is since the other functions are being called.
On the shell prompt, there is no call to the ajax function at all. Help needed.
Pertinent code attached. It is the same as on the website link above.
static/rango-ajax.js
$('.rango-add').click(function(){
var catid = $(this).attr("data-catid");
var title = $(this).atrr("data-title");
var url = $(this).attr("data-url");
$.get('/rango/auto_add_page/', {category_id: catid, url: url, title: title}, function(data){
$('#pages').html(data);
me.hide();
});
});
templates/rango/category.html
{% if user.is_authenticated %}
<button data-catid="{{category.id}}" data-title="{{ result.title }}" data-url="{{ result.link }}" class="rango-add btn btn-mini btn-info" type="button">Add</button>
{% endif %}
rango/views.py
#login_required
def auto_add_page(request):
context = RequestContext(request)
cat_id = None
url = None
title = None
context_dict = {}
if request.method == 'GET':
cat_id = request.GET['category_id']
url = request.GET['url']
title = request.GET['title']
if cat_id:
category = Category.objects.get(id=int(cat_id))
p = Page.objects.get_or_create(category=category, title=title, url=url)
pages = Page.objects.filter(category=category).order_by('-views')
#Adds our results list to the template context under name pages.
context_dict['pages'] = pages
return render_to_response('rango/page_list.html', context_dict, context)
rango/urls.py
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^goto/$', views.track_url, name='track_url'),
url(r'^add_category/$', views.add_category, name='add_category'),
url(r'^auto_add_page/$', views.auto_add_page, name='auto_add_page'),
Complete code is at this link.
your code is good, the only thing what you have to do is to define your template in /tango/templates/rango/page_list.html. This template have the following code:
{% if pages %}
<ul>
{% for page in pages %}
<li>
{{ page.title}}
{% if page.views > 1 %}
({{page.views}} views)
{% elif page.views == 1 %}
({{page.views}} view)
{% endif %}
</li>
{% endfor %}
</ul>
{% else %}
<strong> No Pages currently in category. </strong>
{% endif %}
And inside of your category template you must define the following code:
% if category %}
{% if user.is_authenticated %}
Add a new Page <br>
{% endif %}
{% if pages %}
<div id="pages">
<ul>
{% for page in pages %}
<li>
{{ page.title}}
{% if page.views > 1 %}
({{page.views}} views)
{% elif page.views == 1 %}
({{page.views}} view)
{% endif %}
</li>
{% endfor %}
</ul>
</div>
{% else %}
<strong> No Pages currently in category. </strong>
{% endif %}
{% else %}
The specified category {{ category_name }} does not exist!
{% endif %}
I'm working through this section of the tutorial now and just want to add to Héctor's answer. To avoid duplicating the code to display the list of pages I did the following:
I added a get_page_list() method to tango/rango/templatetags/rango_extras.py, similar to the get_category_list() method used to display a list of categories in an earlier section of the tutorial.
from rango.models import Page
#register.inclusion_tag("rango/page_list.html")
def get_page_list(category):
pages = Page.objects.filter(category=category) if category else []
return {'pages': pages}
Then we just need to load rango_extras and call the get_page_list() method in tango/templates/rango/category.html.
{% extends 'rango/base.html' %}
{% load rango_extras %}
<!-- Existing code -->
{% if category %}
<!-- Existing code to show category likes and like button -->
<div id="page_list">
{% get_page_list category %}
</div>
<!-- Existing code to show search if user is authenticated -->
{% else %]
The specified category {{ category_name }} does not exist!
{% endif %}
This allows you to display the list of pages when a category page is first loaded and then refresh it if a category is added from the search area, without having to duplicate any code.

Categories

Resources