Jinja variable declared in javascript inside a for-loop - javascript

I coded a page using the Flask framework.
I intend to have each line of a table redirecting, on click, to another page.
For that, I used a js object and declared the page using Jinja.
Everything works, but I have an error in the IDE saying:
";" expected Javascript.
So the code is simplified as follows:
<tbody class="table-hover">
{% for x in top %}
<tr onclick="window.location='{{ url_for('example', parameter=x[0]) }}';">
<td class="text-left"> {{ x[1] }} </td>
</tr>
{% endfor %}
</tbody>
Declaring it before solves the syntax alert but doesn't work, as the variable can only have one value on the HTML page.
<tbody class="table-hover">
{% for x in top %}
<script>
let direction = "{{ url_for('example', parameter=x[0]) }}";
<tr onclick= "window.location= direction;">
<td class="text-left"> {{ x[1] }} </td>
</tr>
{% endfor %}
</tbody>
The above code would always redirect to the first x[0]. Should we declare direction with var, it would redirect to the last x[0] of the list.
I tried testing various quotation marks' orders. In the current solution, there is one quotation mark ' ' inside another ' ' which is usually bad. However, replacing the nested one with " " doesn't work. It would give an
Unterminated string literal.javascript
Once again, the first code does give the expected result (and the error doesn't prevent the pages from opening). But there is an error, and I would love to understand why / how to fix it.
Thank you for your help.

Related

Jquery Insert element in an other on event

First post here and quite new on javascript/jquery/webstuff but even after some research about the thing I'm trying to do, I didn't manage to find something that made this thing work.
So, here is the context :
I'm creating a schedule with HTML and Javascript/Jquery.
I want to be able to inject an automated generated <span> or something directly by clicking on the day (which is a <td>).
At first I used basic stuff like "getElementById()" but if I manage to do the thing with this, I'm going on a lot of repetitive code. And I'm quite sure I can avoid this.
So basically I wanted to do generic code and be able to get the which the user clicked.
Here is what I managed to do by now:
HTML part :
<table>
<tr>
<th class="day-name">Sun</th>
<th class="day-name">Mon</th>
<th class="day-name">Tue</th>
<th class="day-name">Wed</th>
<th class="day-name">Thu</th>
<th class="day-name">Fri</th>
<th class="day-name">Sat</th>
</tr>
{% set counter = namespace(a=0) %}
{% for x in range(0, 5) %}
<tr class="week">
{% for y in range(0, 7) %}
{% set counter.a = counter.a + 1 %}
<!-- <td id="2" class="day" onclick="addEvent()"><span class="number">{{ counter.a }}</span></td> -->
<td id="day_{{ counter.a }}" class="day"><span class="number">{{ counter.a }}</span></td>
{% endfor %}
{% endfor %}
</table>
Javascript Part :
function addEvent(){
var node = document.createElement("span");
node.setAttribute("class", "event");
document.getElementById("2").appendChild(node);
};
$(document).ready(function(){
$("td").click(function(){
alert("Ahahahah");
var node = document.createElement("span");
node.setAttribute("class", "event");
document.getElementById(this).appendChild(node);
});
});
The {% ... %} is from Flask/Jinja stuff, but I'm quite sure that's not the problem.
The script is in an other file, but the file is included. (Sure about it because the script "addEvent" works well).
So I tried many, many things, but still not working. The alert pop-up is not even showing up, so I can't try the script. I guess that the way to inject the new element is wrong, but I didn't saw anything with the way I was looking for.
So here it is, thanks in advance for those who take the time to help me on this
I see
onclick="addingEvent()"
but
function addEvent(){
Mabay this is the problem?
You need to use the reference to this and using this can append with it.
$(document).ready(function(){
$("td").click(function(){
alert("Ahahahah");
var node = document.createElement("span");
node.setAttribute("class", "event");
this.appendChild(node);
});
});

Display Product Variant Metafields

I need to display metafields based on the variants selected on the product page. I want them to change as the variants are clicked. I may need some jquery help but I am not that sure how to apply with liquid. Below is my code, any help is greatly appreciated!
{% for variant in product.variants %}
<div id="tab{{ forloop.index0 }}" class="zr-tabs-panel {% if forloop.first == true %}js-active{% endif %}">
<div class="table-responsive>">
<table class="table table-striped">
<tbody>
{% for field in current_variant.metafields.var_meta %}
<tr>
<td>{{ field | first }}</td>
<td>{{ field | last }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endfor %}
The short answer is that you will need to (a): Expose your meta fields to your site's javascript somehow, then (b): Update your variant-changing code to also update the section based on your meta fields.
In many themes, the variant-changing code is contained in a function named selectCallback (though this isn't the case in all themes - if you have trouble finding this code, you can try reaching out to your theme's developer for theme-specific advice).
Whenever you're using Liquid code to put values into Javascript code, I strongly recommend using the json filter - Liquid's magic filter that ensures your output will always be Javascript-legal. (Quotation marks and line breaks will be properly escaped, empty values will be printed as null, etc)

How to check if one JS script is not loaded twice or more?

I'm working in Symfony Project, with Twig template engine.
I have a form.html.twig file where I have One big form, and one little that can be generated as many times as I want.
So, when I press the "+" button, a new sub-form appears.
This form appears from prototype.html.twig file, where is stored all HTML of the form, with included JS.
It looks like :
<table class="table table-responsive table-bordered text-center" style="margin-bottom:0px;">
<tr class="active">
<td style="vertical-align:middle; padding-top:9px; padding-left:4px; padding-right:4px;"> <span style ="font-size: 24px;" class="glyphicon glyphicon-upload"></span></p> </td>
<td>{{ form_row(form.date) }}</td>
<td>{{ form_row(form.value) }}</td>
<td> {{ form_label(form.type, 'Value as % of') }}
{{ form_widget(form.type) }} </td>
<td>{{ form_row(form.frequency) }}</td>
<td>{{ form_row(form.duration) }} </td>
<td>{{ form_row(form.agreement) }}</td>
<td class="deleteButton" style="vertical-align:middle;"><button class="btn-sm btn-danger" style="border-radius:100%;"><span class="glyphicon glyphicon-remove"></span></button></td>
</tr>
</table>
<script>
$('.deleteButton').on('click', function(e) {
e.preventDefault();
$(this).parent().remove();
});
</script>
{% block javascripts %}
<script src="{{asset('js/endingDateCalculator.js')}}"></script>
{% endblock javascripts %}
Take a look to block javascripts. In this block I have a script that calculate ending date in my sub-form. So, once I click the "+" button appears a new form, and the script endingDateCalculator is running and connected to work with this form.
I'm a little bit afraid that if I click more than one time to "+", with other words...if I have more than 1 sub-forms, this script is called again and again, that slows the page speed, or/and can make bugs with working in the same time.
It is calling again and again or not?
If yes, how can i solve it?
I tried to link the endingDateCalculator.js to the form.html.twig (base template), but in this case this script is not working when I generate a new form.
not sure about symfony, but one of the options may be this
<script src="//ajax.aspnetcdn.com/ajax/jquery/jquery-2.0.0.min.js"></script>
<script>window.jQuery || document.write('<script src="js/jquery-2.0.0.min.js">\x3C/script>')</script>
=========
from https://www.hanselman.com/blog/CDNsFailButYourScriptsDontHaveToFallbackFromCDNToLocalJQuery.aspx

Combining ng repeat and django template language

I have a table that will have varying columns over time and I want my django view to support those changing columns. I also want to use ng-repeat to do some fancy stuff with it such as filtering and other things. However I am having trouble combining the two.
I am passing in the arbitrary col_names with django template language. packages is also sent in with the django template language and is essentially a json array where each row is a dict mapping col_name to some value. i.e.
$scope.packages = [{'col1': 'row1col1', 'col2': 'row2val2'}, {'col1': 'row2col1' ....
However when I go to put in the rows using packages I can't "nest" my templates. Is there a way to grab arbitrary values out of each row in `packages?
<input ng-model="search" placeholder="Search">
<table style="width:100%;">
<thead>
<tr>
<th>Permanent Column 1</th>
<th>Permanent Column 2</th>
{# changing columns #}
{% for col_name in col_names %}
<th>{{ col_name }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
<tr ng-repeat="package in packages | filter:searchPackage">
{% for col_name in columns %}
<td>{{package.{{ col_name }}}}</td> DOESN'T WORK!
{% endfor %}
</tr>
</tbody>
</table>
In that problem line I essentially want to have {{package.ACTUAL_ARBITRARY_COL_NAME}} but I don't know how to do that programmatically
The problem
By default, Django and AngularJS use the same tokens {{ and }} for templating.
So this gets first processed by Django template
{% for col_name in columns %}
<td>{{package.{{ col_name }}}}</td> DOESN'T WORK!
^ ^
|________________________|
Django template will try to process this value
Because Django tries to expand what's inside the first {{...}}, you will not get what you want AngularJS to see.
If you want to continue down that road, I suggest you read some solutions to this problem here
Better solution
A better approach is to give AngularJS the items you want Django to loop for you.
$scope.columns = [...];
Then use AngularJS to do all the loops. Whichever way you do it, if you need it done in AngularJS, better do it all in AngularJS and not half-Django half-AngularJS.

How to get the page back and not refresh after submitting form in django

reffering to my title above:
patientdetails.html
<form id="content" action="{% url patientdetails_view pk %}" method="post" >
{% csrf_token %}{{form.owner}}
------
<tbody><tr>
<td><input type="submit" value="Save" >
------
patientList.html
{% for patient in patienter %}
<tr class = {% cycle "row_even" "row_odd" %}>
<td>{{ patient.id }}</td>
<td> {{ patient.Personnummer }}</td>
<td class ="name"> {{ patient.first_name }} {{ patient.last_name }}</td>
{% endfor %}
here is my question
My program flow like this. I have to click to a list of names in patientList.html and edit some data in patientdetails.html and after i made the changes how do i get back to patientList.html after i have done some changes in patientdetails.html and save. i have to click twice to get back to the original page. the first click refreshing and save the data and the second click back to the original page.
why is it doing that. what did i missing here.
how do i do alert stated"Data are saved".
I'm very very new to django. I'm totally lost in here.
You can redirect to a url after completion of your form processing in the view that handles patient detail updates. You can use HttpResponseRedirect() to do this. This is very basic in django refer docs Using a form in a view
For #2, you can make use of django messages framework to pass messages. Through templates you can show a message wherever you feel appropriate.

Categories