passing variable in javascript function using django template - javascript

here I am passing {{id}} to hide_show(...) javascript function
{% for stock in part_temp.part_stock_set.all %}
{% with id="list"|concatenate:stock.id %}
<div id="{{ id }}">
{{ stock.entry_date}}
</div>
<button type="button" onclick="hide_show({{ id }})">edit</button>
<br>
{{ id }}
here above the {% endwith %} {{ id }} is displaying correctly but the hide_show function in not called but it is called when just {{ stock.id }} is passed to it.
the concatenate filter just concatenates and returns a string.
<script type="text/javascript">
function hide_show(temp) {
document.getElementById(temp).style.display='none';
window.alert(temp);
}
</script>

Problem seems to be with the quotes. if {{ id }} returns a string, then you don't have to put quotes here
<div id="{{ id }}">
Simply replace it with:
<div id={{ id }}>
If id is an integer or if the above doesn't work, then you have to put quotes here as well as in the argument while calling the hide_show function.

Related

Automatically add divs to product descriptions in Shopify

I'm trying to add divs to product descriptions in Shopify so that I can then create an accordion.
Currently my code looks like this
In the .liquid file:
<div class="product-single__description rte">
{{ product.description }}
</div>
This is the output:
<div class="product-single__description rte">
<h2>TEXT</h2>
<h4>TEXT</h4>
<p><em>Text</em></p>
<h4>TEXT</h4>
<p>Text</p>
<h2>TEXT</h2>
<h4>Text</h4>
<p>Text</p>
<h4>TEXT</h4>
<p>Text</p>
<h4>TEXT</h4>
<p>Text</p>
<p><em>Text</em></p>
</div>
My goal is to insert a div wrapper and enclose the content from H2 to the next h2, so for example:
<div class="product-single__description rte">
<div class=“class_1”
<h2>TEXT</h2>
<h4>TEXT</h4>
<p ><em>Text</em></p>
<h4>TEXT</h4>
<p>Text</p>
</div>
<div class=“class_2”
<h2>TEXT</h2>
<h4>Text</h4>
<p>Text</p>
<h4>TEXT</h4>
<p >Text</p>
<h4>TEXT</h4>
<p>Text</p>
<p><em>Text</em></p>
</div>
</div>
The number of H2s and the content changes from product to product.
Well there are a few checks that you need to make before you do this.
First we will set a variable for the content:
{% assign content = product.description %}
After that we will check if the if there is a plain <h2> in there
{% if content contains '<h2>' %}
// logic to add here
{% else %}
{{content}}
{% endif %}
(have in mind that if your h2 tags have any inline styles you will have to target <h2 instead)
If there is we will continue the logic inside the if, but if there is not we will output the plain content in the else statement.
So we are now in the // logic to add here part here.
We will split the content by <h2> like so:
{% assign content_arr = content | split: '<h2>' %}
We will check if you have some content before the first <h2> since we don't want to loose it in that case, so we check it like so:
{% if content_arr[0] != '' %}
{{content_arr[0]}}
{% endif %}
We need to loop the rest of the items of the array.
Since we are splitting by <h2> if there is no content before the <h2> it will return an empty array for the first item and we don't need that one. So we will offset the for loop by 1 item:
{% for item in content_arr offset: 1 %}
// items here
{% endfor %}
Now we need to return the opening <h2> tag (since we removed it from the content) and show the rest of the content.
It's easy as writing <h2> before the {{item}}:
<div class="class_{{forloop.index}}">
<h2>{{item}}
</div>
And that's all.
Here is the full code:
{% assign content = product.description %}
{% if content contains '<h2>' %}
{% assign content_arr = content | split: '<h2>' %}
{% if content_arr[0] != '' %}
{{content_arr[0]}}
{% endif %}
{% for item in content_arr offset: 1 %}
<div class="class_{{forloop.index}}">
<h2>{{item}}
</div>
{% endfor %}
{% else %}
{{content}}
{% endif %}
You may try this (not tested but it should work):
{% assign desc_parts = product.description | split:'<h2>' %}
{% for part in desc_parts offset:1 %}
<div class="class_{{ forloop.index }}">
{{ part | prepend:'<h2>' }}
</div>
{% endfor %}
Explanations:
As you do not have clean separator in product description, let's use
h2 tag.
Then, you create an array with this separator (split
function).
Then you loop through your array, with an offset to 1 to
avoid the empty first elem (or you may use it later or before to display it in a separated div it there is something before the first h2 tag). To display separately the first elem, use {{ desc_parts.first }}.
To get a unique class or id, you may
use the loop index.
As the h2 tag is the separator used to create
the array, you need to prepend your elem with it.
Please note that you should also think about the case with a product description without h2 and manage this case in your code.

How do I populate dynamically a StringField with the value of a SelectField in Wtforms

in a wtforms, I would like my SelectField to fill up with its selected value a StringField.
I use flask, bootstrap, and python 3.7
My HTML code is as follow:
{% block body %}
<h3>Edit Bloomberg ticker details</h3>
{% from "includes/forms/_form_helpers.html" import render_field %}
<div class="form-group" id="company_id" onchange="myFunction(event)">
{{render_field(form.company_names, class_="form-control")}}
</div>
<div class="form-group" id="isin_id">
{{render_field(form.isin_id, class_="form-control")}}
</div>
<script>
function myFunction(e) {
document.getElementById("isin_id").value = e.target.value
}
</script>
{% endblock %}
And the pyhon behind is as follow:
class DefTickerForm(_Form):
choices_companies = [(1,'Facebook'), (2, 'Google') ]
company_names = _SelectField(label='Company names:', choices=choices_companies, coerce=int)
isin_id = _StringField(label='isin_id', validators=[_validators.DataRequired], default=-1)
I would like that when the user select 'Facebook', the isin SelectField to be equal to 1. But so far it does nothing.
Note that if if code:
alert(e.target.value)
I get the wanted value. so issue is to set the TextField value.
my render field code is as followed (from a youtube tutorial):
{% macro render_field(field) %}
{{ field.label }}
{{ field(**kwargs)|safe }}
{% if field.errors %}
{% for error in field.errors %}
<span class="help-inline"> {{ error }}</span>
{% endfor %}
{% endif %}
{% endmacro %}
Any help would be much apreciated as google isn't so good on these.
Best
apparently TextField only accepts strings (I guess obvious if you are used to javascript)
so code working is as follow in case someone get he same problem:
<div class="form-group" onchange="myFunction(event)">
{{render_field(form.company_names, class_="form-control")}}
</div>
<div class="form-group">
{{render_field(form.isin_id, class_="form-control")}}
</div>
<script>
function myFunction(e) {
var x = e.target.value;
alert(x);
document.getElementById("isin_id").value = x.toString();
}
</script>
As a note, Jinja or anyway my render, use the fields names as default IDs (wich i realised using Chrome inpector. Meaning I didn't have to add an id for each Div. Anyway that is the thoughts of a beginenr in Javascripts.

calling javascript function inside html element and jinja2?

i have this code:
{% for review in reviews %}
<div>
{{ review.content }}
by {{ review.username }}
- timeDifference("{{ review.date_submitted }}")
</div>
{% endfor %}
on the 5th line is a js function timeDifference that will return time difference in text, I want to insert js function there, how do I do that?
this is the solution that worked for me, inspired by Raja Simons' answer and How to add onload event to a div element?:
<div id="review{{review.id}}">
{{ review.content }} by {{ review.username }}
-
<p id="timeDifferenceElement{{ review.id }}"></p>
<script type="text/javascript">
timeDifferenceForDate( '{{ review.id }}', '{{ review.date_posted }}' );
</script>
Execute Js function like that is not possible. And what possible is during onload time execute the javascript function and do DOM manipulation.
In Html
<-- In for loop -->
<div onload="timeDifference( {{ review.id }}, {{ review.date_submitted }} );">
<p id="timeDifferenceElement{{ review.id }}"></p>
</div>
In Javascript
function timeDifference(id, date_submitted) {
const timeDifferenceElement = document.getElementById("timeDifferenceElement" + id)
// Do calculation
---
timeDifferenceElement.innerHTML = "something from the calculation"
}

Calling a method individually by class selector

In my blog I'm using Pico CMS, in the index.twig page I wrote this code that generates HTML with page title, description, and URL:
{% for page in pages|sort_by("time") %}
{% if page.id starts with "blog/" %}
<div class="post">
<h3>
<a class="page-title" href="{{ page.url }}">{{ page.title }}</a>
<small class="date">{{ page.date }}</small>
</h3>
<p class="excerpt">{{ page.description }}</p>
{% endif %}
{% endfor %}
My idea was to make each title in a different color, I used randomColor, and wrote this JavaScript:
$('.page-title').css('color', randomColor() );
But this makes all the page-titles in the page to be of same color, I would like each of them in a different color.
This is the website: blog.lfoscari.com
$('.page-title').css('color', randomColor() ); in plain english is Call the function randomColor() and get the colour and then set the same to all the elements matching the class.
You've to use each() to iterate over all elements, get the random colour by calling the function and set it to each element individually.
$('.page-title').each(function() {
$(this).css('color', randomColor())
});
You can use css() with callback , it will iterate over elements and you can update value by returning
$('.page-title').css("color", randomColor);
<script src="https://cdnjs.cloudflare.com/ajax/libs/randomcolor/0.4.4/randomColor.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="page-title">1</div>
<div class="page-title">1</div>
<div class="page-title">1</div>
<div class="page-title">1</div>
<div class="page-title">1</div>
<div class="page-title">1</div>
Twig has a random function that you can use:
<a class="page-title"
style="color: {{ random(['orange', 'pink', 'LightSkyBlue']) }}"
href="{{ page.url }}">{{ page.title }}</a>

Add Like button with Django + Ajax

Hi I create my first project like stackoverflow(question-answer). I used this guid from Tango with Django http://www.tangowithdjango.com/book17/chapters/ajax.html to add like button with ajax. And nothing hapened. Don't see any request in console. I'm noob in Django, and it's my first encounter with jquery.
apps/questions/models:
class Answer(models.Model):
text = models.TextField()
date = models.DateTimeField(default=datetime.datetime.now)
likes = models.IntegerField(default=0)
resolve = models.IntegerField(default=0)
author = models.ForeignKey(CustomUser)
question = models.ForeignKey(Question)
apps/questions/views:
#login_required
def add_like(request):
ans_id = None
if request.method == 'GET':
ans_id = request.GET['answer_pk']
likes = 0
if ans_id:
ans = Answer.objects.get(id=(int(ans_id)))
if ans:
likes = ans.likes + 1
ans.likes = likes
ans.save()
return HttpResponse(likes)
apps/questions/ulrs:
url:
url(r'add_like/$', views.add_like, name='add_like'),
question.html:
{% for answer in answers %}
<div class="container-fluid no-padding">
{{ answer.text }}
</div>
<div class="container-fluid author-question">
<p>posted: {{ answer.date.day|stringformat:"02d" }}.{{ answer.date.month|stringformat:"02d"}}.{{ answer.date.year}}</p>
<p>by: {{ answer.author.username }}</p>
</div>
{% if user.is_authenticated %}
<button class="btn btn-default" type="button" id="likes" data-ansid="{{ answer.id }}">
like | <strong id="like_count">{{ answer.likes }}</strong>
</button>
{% endif %}
js/ajax.js:
$('#likes').click(function(){
var ansid;
ansid = $(this).attr("data-ansid");
$.get('/questions/add_like/', {answer_id: ansid}, function(data){
$('#like_count').html(data);
$('#likes').hide();
});
});
Since you are creating buttons in a for loop, and naming them the same way, you have multiple elements on the page with the same id. Because of this you get unpredictable results. You should either give each button its own id, or change the jQuery selector to select the buttons based on the appropriate class.
For example, you could have:
{% for answer in answers %}
<div class="container-fluid no-padding">
{{ answer.text }}
</div>
<div class="container-fluid author-question">
<p>posted: {{ answer.date.day|stringformat:"02d" }}.{{ answer.date.month|stringformat:"02d"}}.{{ answer.date.year}}</p>
<p>by: {{ answer.author.username }}</p>
</div>
{% if user.is_authenticated %}
<button class="btn btn-default likes-button" type="button" data-ansid="{{ answer.id }}">
like | <strong id="like_count">{{ answer.likes }}</strong>
</button>
{% endif %}
{% endfor %}
And then for the javascript
$('.likes-button').click(function(){
var ansid;
ansid = $(this).attr("data-ansid");
$.get('/questions/add_like/', {answer_id: ansid}, function(data){
$('#like_count').html(data);
$('#likes').hide();
});
});

Categories

Resources