I am trying to use a javascript variable in a python dictionary in html, is this possible? Any help would be great.
e.g if I had a dictionary - current_data
var num_key = "4";
alert( {{ current_data[num_key] }} );
If I do the following it works perfectly,
alert( {{ current_data["4"] }} );
But with the javascript variable, it won't work.
Thanks again.
No, while you can use Jinja to create JavaScript embedded in <script> tags, you cannot use it the other way around. When Flask renders this page it's static. The page does not still have blocks of code inside {{ }} or {% %}, it holds the result of those operations. However, there are other options. You could put the contents of current_data into hidden input with the keys as the id attributes.
View
{% for key in current_data %}
<input id="{{ key }}" type="hidden" value="{{ current_data[key] }}"/>
{% endfor %}
JavaScript
var num_key = "4";
alert(document.getElementById(num_key).value);
One extra piece of advice, it's not good practice to embed JavaScript into your html. You should have a separate .js file containing this and then include it in your html.
Related
Problem
I'd like to add a small bit of client-side JavaScript to my Eleventy website. I can't seem to access document. using Eleventy which means I can't access elements and listen to them for events. Example of what doesn't work:
const formElement = document.querySelector("form")
The error message I receive from Eleventy:
ReferenceError: document is not defined
Question
How do I work with Eleventy in order to listen to document element changes and make page changes?
Example:
formElement.addEventListener("change", function () {
// Update nearby paragraph element based on form value
});
My real-world scenario: I would like to have a paragraph element display which of the form's input type="radio" has the value checked.
Approach so far
I have a file in /data called fruits.json:
{
"items": [
{
"name": "Apple"
},
{
"name": "Banana"
},
{
"name": "Strawberry"
},
{
"name": "Mango"
},
{
"name": "Peach"
},
{
"name": "Watermelon"
},
{
"name": "Blueberry"
}
]
}
And a HTML file in /_includes/layouts based on my base.html file:
{% extends "layouts/base.html" %}
{% block content %}
<form>
{% for item in fruits.items %}
{# Create a radio button for each, with the first one checked by default #}
<input type="radio" name="screen" id="{{ item.name | slug }}" value="{{ item.name | slug }}" {% if loop.index === 1 %} checked {% endif %}>
<label for="{{ item.name | slug }}">{{ item.name }}</label>
{% endfor %}
{% set selectedFruit = helpers.getSelectedFruit() %}
<p>Currently selected item from above is: {{ selectedFruit }}</p>
</form>
{% endblock %}
Note that thee variable called selectedFruit is assigned to a helper function:
{% set selectedScreen = helpers.getSelectedScreen() %}
That getSelectedScreen() function looks like:
getSelectedScreen() {
const formEl = document.querySelector("form")
console.log(formEl)
}
Aside from not being able to work with .document, I feel like this approach is probably 'against the grain' of Eleventy, static site generators in other ways:
The script is being called mid-document
The script is one-off and away from its context
I wonder if I'm approaching this wrong in the first place, or if I just need to do something to allow .document access.
There are some misconceptions here — the most important distinction for your JavaScript code is whether it's executed at build time or client-side at runtime.
The Eleventy core as well as your .eleventy.js configuration file are written in JavaScript which is executed once during the build step, i.e. when your static site is being generated. This happens in a NodeJS environment, not in a browser, which is why there's no document variable and and no DOM.
If you want to dynamically change something on your site in response to user interaction, you need to write a separate JavaScript file which is copied to the output directory of your static site. Then you can include it in the HTML template for your static sites so it's included during normal page visits after your site is deployed.
First, modify your template to only generate a placeholder element for your JavaScript function to add text to later:
{% extends "layouts/base.html" %}
{% block content %}
<form id="fruits-form">
{% for item in fruits.items %}
{# Create a radio button for each, with the first one checked by default #}
<input type="radio" name="screen" id="{{ item.name | slug }}" value="{{ item.name | slug }}" {% if loop.index === 1 %} checked {% endif %}>
<label for="{{ item.name | slug }}">{{ item.name }}</label>
{% endfor %}
<p id="selected-fruits-output"></p>
</form>
{% endblock %}
Then, create a JavaScript file which reacts to change events on the form:
// fruit-form.js
const fruitForm = document.getElementById('fruits-form');
const formOutput = document.getElementById('selected-fruits-output');
fruitForm.addEventListener('change', e => {
// update the formOutput with the list of selected fruits
});
Now you need to make sure this javascript file is copied to your output directory, using Passthrough file copy:
eleventyConfig.addPassthroughCopy("path/to/fruit-form.js");
Finally, make sure to include the script element in your HTML template (make sure the path is an absolute path to the output as specified above):
{# layouts/base.html #}
<script src="/path/to/fruit-form.js" defer></script>
Now it should work as expected. In general, make sure to understand the difference between build-time and runtime JavaScript, so you can decide which will work best in different situations.
I want something like this inside django template. I want to use these variables in javascript file or another template file.
{% set titles = {
'table': form._meta.model._meta.verbose_name_plural.title(),
'form': form._meta.model._meta.verbose_name.title()
}
%}
{% set dtable = "dt_" + page %}
How can I create "set tag" in django template? Your answer would be helpful for me.
Although I think this is generally to be avoided (mixing template & logic is generally advised against in django), it appears this is possible through the use of the with tag.
{% with name="World" greeting="Hello" %}
<html>
<div>{{ greeting }} {{name}}!</div>
</html>
{% endwith %}
In javascript, it would probably look like this
$(document).ready(function(){
{% with greeting="hello" %}
var text = '{{ greeting }}'
{% endwith %}
});
There are some constraints, I don't believe you can set tuples or dictionaries this way. That said, if you're trying to set more complex types using {% with ... %} that logic should probably be handled in the view.
Referenced from this SO question.
CASE 1:
If you want to access your dictionary in the HTML template. You can pass titles dictionary to the template and access any key of the dictionary by the dot (.) operator.
<div class="something1">{{ titles.table }}</div>
<div class="something2">{{ titles.form }}</div>
CASE 2:
If you want to send a dictionary to the HTML template and access in your javascript file, I would suggest you to store them in a data attribute of an input (hidden) element or any element and then access via javascript.
<input type="hidden" id="my-data-table" data-table="{{ titles }}">
You can access dictionary in your javascript file like this,
var myTitles = document.getElementById("my-data-table");
var titles = myTitles.getAttribute("data-table");
For example, if I have this code:
<form action="{{ url_for('user.new_domain') }}" class="form" role="form" method="post" action="" autocomplete="off">
{{ form.csrf_token }}
<p>{{ form.name(placeholder="name", onkeyup="timing()") }}
<span class="error">
{% if form.name.errors %}
{% for error in form.name.errors %}
{{ error }}
{% endfor %}
{% endif %}
</span>
</p>
</form>
timing() is a function within a javascript file that I have inside a <script> tag in my code. I want timing() to be able to access my sqlite database info and check to see if whatever the user entered into the form exists in my database. Is this even the right way to do this? Through javascript? how else am I supposed to run javascript functions that are dependent on sqlite data? Any help is appreciated. Thanks!
Use Ajax to send a call to another route in your app that returns a string (plain or JSON, whichever is more useful). The Ajax call then uses it's success function to parse that data and act on it as appropriate.
So, in addition to your code that is only rendered by Flask:
{% if form.name.errors %}
{% for error in form.name.errors %}
{{ error }}
{% endfor %}
{% endif %}
you'd need to act via JavaScript:
<script>
function timing() {
$.ajax({
method: "POST",
url: "some url",
data: {
key: "value"
},
success: function(data) {
// do something
}
});
}
</script>
and the code in your app would be something like (based on the fact that your results are coming from another Python file that actually does the querying):
from that_other_file import the_querying_function
#app.route('/some_url', methods=['POST'])
def some_url():
return the_querying_function(request.POST['key'])
This uses HttpResponse.POST. Replace key (in the JS and Python) with whatever you're trying to get from the form.
Short answer is yes it is possible but on limited browsers, see the link for details. http://html5doctor.com/introducing-web-sql-databases/
Long answer is it might be smart to use your backend to access these (perhaps through an API?) Here's one such example for Flask (although I am not sure what you are using https://flask-restless.readthedocs.org/en/latest/)
I have an html file in which i have set a variable called flxweb_user inside the script tag. In the same html i am using jinja. I need to check if this value for flxweb_user matches a specific value and so need to access this variable inside jinja if condition.
Sample code:
<script type="text/javascript">flxweb_user = somevalue;</script>
jinja if statement in which i need to check this value
{% if c.user.role.name == 'teacher'%}
<span>
{{ item.display_label() }}
</span>
{% endif %}
I'm dynamically generating forms with hidden input in a webpage using django templates, which should be submitted when clicking on some associated text label. The problem is that I just can't get it to work.
{% for tag in tags %}
<form name="remove_{{ tag }}" id="{{ tag }}" action="/filter" method="post" accept-charset="utf-8">
<input type="hidden" name="remove_tag" value ="{{ tag }}" />
</form>
{{ tag }}
{% endfor %}
<script type="text/javascript">
function remove_tag(tag) {
document.getElementById(tag).submit();
return false;
}
</script>
This code generates the following javascript error: Uncaught TypeError: Cannot call method 'submit' of null
I've also tried submitting the form using
document.forms[tag].submit();
(changing the form name to tag), but receive pretty much the same error but with 'undefined' instead of null.
In the second example, it looks like the javascript function tries to interpret 'tag' as an integer. If I do use an integer it works alright. I could use the forloop.counter used to generate the forms in the first place, but that is kind of ugly and makes the code harder to maintain.
Is there any other, functioning, way of calling submit() on the forms?
Quotes:
{{ tag }}
The "tag" value has to be properly quoted for the Javascript snippet to be syntactically correct.