Access Django variable from JavaScript variable - javascript

First of all, I will like to say this is my first question here! (pardon me if this is redundant or duplicated)
I am having some problems with calling JS scripts from Django template:
{% for suggestion in suggestions %}
<img class="catalogue-poster" src="{{ suggestion.poster }}" alt="Portada" onclick="
document.getElementById('{{form.title.auto_id}}').value = '{{suggestion.title}}'
document.getElementById('{{form.year.auto_id}}').value = '{{suggestion.year}}'
document.getElementById('{{form.director.auto_id}}').value = '{{suggestion.director}}'
document.getElementById('{{form.rating.auto_id}}').value = '{{suggestion.rating}}'
document.getElementById('{{form.poster.auto_id}}').value = '{{suggestion.poster}}'
document.getElementById('{{form.trailer.auto_id}}').value = '{{suggestion.trailer}}'
document.getElementById('{{form.synopsis.auto_id}}').value = '{{suggestion.synopsis}}'
document.getElementById('{{form.cast.auto_id}}').value = '{{suggestion.cast}}'
" />
{% endfor %}
So, first of all, how can I declare a function outside. I'm a C developer, sorry for my ignorance.
I've tried to create a script outside, such as
<script>
function foo() {
console.log('Hey');
});
</script>
And invoke it this way:
<img class="catalogue-poster" src="{{ suggestion.poster }}" alt="Portada" onclick="foo()"/>
But this simple thing that works on pure HTML, with django templates does not seem to work...
On the other hand, the real question was, is there a way to access a Django variable passed in render with a js variable?
Such as:
const jsVariable = 'title';
document.getElementById('{{form.jsVariable.auto_id}}').value = '{{suggestion.jsVariable}}'
I have not found any way to accomplish this, maybe there is another great idea!

I have tried one example. where is send a variable from python script and access its value in JavaScript
1) In views.py
from django.shortcuts import render
def home_view(request):
var_name = 'hello'
return render(request, 'home.html', {'var_name':var_name})
2) In html file(home.html)
<html>
<h1>Home Page</h1>
<input type="button" value="Submit" onclick="fun()">
<script>
function fun(){
console.log('hello world '+ '{{var_name}}' );
}
var temp = '{{var_name}}';
console.log(temp + 20);
</script>
</html>
If i click submit button ( hello world hello ) is printed in console.
I stored value of var_name in temp which can be further used.

From your example, it looks you want to programmatically access a Django model's attribute in Javascript.
The main takeaway is that you first need to expose the data structure you want to access (i.e. the model) in Javascript.
Here's a simple, redacted, proof-of-concept you can try.
import json
def my_view(request):
obj = MyModel.objects.get(1)
obj_dict = {
"foo": obj.foo,
"bar": obj.bar,
}
return render(request, 'my_view.html', context={'obj_json': json.dumps(obj_dict)} )
<script>
var obj = {{obj_json}};
var field = 'foo';
console.log(obj[field]);
Check out Convert Django Model object to dict with all of the fields intact for a run-down on options to serialize Django models into dictionaries.

Well, finally I found a solution for both exposed problems.
First of all, the script function I declared was not working because it seems that there is an attribute called autocomplete (see autocomplete HTML attribute)
So, you can not declare a JavaScript function with this name, my fail.
Uncaught TypeError: autocomplete is not a function
Finally, the simple solution I found was passing an array of dicts to the template:
return render(request, 'example.html', {'form': form, 'suggestions': suggestions })
And then in the template:
{% for suggestion in suggestions %}
<img src="{{ suggestion.poster }}" onclick="autocompleteMovie({{suggestion}});" />
{% endfor %}
<script>
function autocompleteMovie(suggestion){
for (let field in suggestion)
document.getElementById('id_' + field).value = suggestion[field]
}
</script
Which, comparing it with the question, really simplifies the problem.

Related

use javascript to display django object

I want to implement below using javascript so row click it will get index and display object of this index.
in django template this is working.
<div>{{ project.0.customer_name}}</div>
<div>{{ project.1.customer_name}}</div>
but the below javascript are not working even I get the correct ID.
var cell = row.getElementsByTagName("td")[0];
var id= parseInt(cell.innerHTML);
// not working
document.getElementById('lblname').innerHTML = '{{ project.id.customer_name}}';
// this is also working but what I want is dynamic base on row click
document.getElementById('lblname').innerHTML = '{{ project.1.customer_name}}';
display django object using index in javascript.
You have to understand what is happening with your code:
Templates like this are processed on the server:
'{{ project.id.customer_name}}'
I believe you do not have project.id on your server side, so you get None in the above line, and the moustache tag becomes smth like an empty string, and actual JavaScript code is like this:
document.getElementById('lblname').innerHTML = '';
It is only now that JS code is executed, and you can imagine what it will do.
What you want is processing moustache tags after the id variable has been set in JS, which is not how stuff works (at least, if you don't have some crazy tool chain).
One way of achieving what you want is to provide the whole project object (or array) to JavaScript by doing the following:
<script>
const project = {{ project|safe }};
</script>
A complete Django template could look like this (I used <span>s instead of table cells:
<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>django test</title>
</head>
<body>
{% block content %}
{% for item in project %}
<span data-id="{{ forloop.counter }}">{{ forloop.counter }}</span>
{% endfor %}
<div id="output" style="display: flex; flex-direction: column-reverse;">
</div>
<script>
const project = {{ project|safe }};
const spans = document.getElementsByTagName('span');
const output = document.getElementById('output');
const onSpanClick = (event) => {
const id = parseInt(event.target.getAttribute('data-id'), 10) - 1; // forloop.counter is 1-based, JS arrays are 0-based
const div = document.createElement('div');
div.innerHTML = project[id].customer_name;
output.appendChild(div);
}
Array.from(spans).forEach(span => {
span.addEventListener('click', onSpanClick);
})
</script>
{% endblock %}
</body>
</html>
Another way is the AJAX way: you create an API endpoint on your server side, so that an URL like example.com/api/customer_name/?id=999 responds to you with the name of customer id=999 when you click on some element and trigger an XMLHttpRequest with param id=999.

how to pass js value to flask route

This is my list where i tried to get the value of the of a tag
{% extends 'base.html'%}
{% block body %}
<div onclick="pass()">
{{list1[1]}}
</div>
here i tried to get the value of a tag and have tried to pass info route
<script>
function pass() {
var a = document.getElementsByTagName('a');
var w = console.log(a[0].outerHTML);
window.location = "/info/" + w;
}
</script>
{% endblock %}
but show the following error
Not Found
http://127.0.0.1:5000/info/undefined
this is my info route
#app.route('/info', methods=['GET', 'POST'])
def info():
result = request.get_data
print(result)
return render_template('info.html', result=result)
why it's not displaying any data of within a tag
Thank you in Advance
window.location simply opens an HTML page. window.location = "/info/" + w; creates a route /info/w/ but you've only specified the route /info.
You need to send the a data to the server via a form and use Flask's request object to access it.

Django template Javascript passing a python variable to a javascript one

I did create a python function called generate_random_number that generate a random number between 1 and 9 and compare it to the id of each video in my database and return the url of the video corresponding to the id matching the random number. Here is the function:
from random import randint
from dash_interface.models import Video
from django import template
register = template.Library()
#register.simple_tag
def random_video():
random_number = randint(1, 9)
all_videos = Video.objects.all()
for video in all_videos:
if video.id == random_number:
random_url = video.video_url
return random_url
I want to pass random_url to a javascript variable in a django template.
My template looks like this:
<video id="videoplayer" controls></video>
<script>
{% load generate_random_number %}
// setup the video element and attach it to the Dash player
function setupVideo() {
var url = " ";
var context = new Dash.di.DashContext();
var player = new MediaPlayer(context);
player.startup();
player.attachView(document.querySelector("#videoplayer"));
player.attachSource(url);
}
</script>
<style>
video {
width: 60%;
height: 40%;
}
</style>
The variable concerned is url.
I did a {% load generate_random_number %}, but I don't know if I can replace the quotation marks in url by {{ random_url }}.
If you want to split the javascript code and html code, you could make something like:
<script arg = {{ somevar }} src = "/path/to/script"></script>
and in the script :
var arg = $("script[src='/path/to/script']").attr("arg");
If you need that the arg will be updated each a concrete period, you need to make an ajax. If you use the database for persist the arg, you could use Django Channels like a more elegance solution.
You should keep the custom template tag definitions in a templatetags folder inside your app. Make sure that __init__.py is present in the templatetags folder. Your folder structure should be similar to:
your_django_app/
__init__.py
models.py
templatetags/
__init__.py
template_tags.py
views.py
And the contents of template_tags.py should be you required tag definition:
from random import randint
from dash_interface.models import Video
from django import template
register = template.Library()
#register.simple_tag
def random_video():
random_number = randint(1, 9)
all_videos = Video.objects.all()
for video in all_videos:
if video.id == random_number:
random_url = video.video_url
return random_url
Note: The templatetags file should contain the variable named register.
After this you can load the template tags in your HTML. Your code will look like:
<video id="videoplayer" controls></video>
{% load template_tags %}
<script>
// setup the video element and attach it to the Dash player
function setupVideo() {
var url = "{% random_video %}";
var context = new Dash.di.DashContext();
var player = new MediaPlayer(context);
player.startup();
player.attachView(document.querySelector("#videoplayer"));
player.attachSource(url);
}
</script>
<style>
video {
width: 60%;
height: 40%;
}
</style>
This is the way I prefer to connect Django templates and JS.
You need to import render function:
views.py file
from django.shortcuts import render
from random import randint
from dash_interface.models import Video
def random_video(request):
random_number = randint(1, 9)
all_videos = Video.objects.all()
for video in all_videos:
if video.id == random_number:
random_url = video.video_url
context = {
"random_url": random_url
}
return render(request, "app/video.html", context)
else:
return render(request, "app/video.html", {})
video.html
<video id="videoplayer" controls></video>
<script>
{% load generate_random_number %}
// setup the video element and attach it to the Dash player
function setupVideo() {
// using the context passed in here.
var url = {{ random_url|safe }};
var context = new Dash.di.DashContext();
var player = new MediaPlayer(context);
player.startup();
player.attachView(document.querySelector("#videoplayer"));
player.attachSource(url);
}
</script>
<style>
video {
width: 60%;
height: 40%;
}
</style>
What I have done is rendered your HTML page in the Django view and passed your variable inside the context dictionary which is later accessible in your HTML tags or script tags.
I also used a |safe parameter in the template tag which removes some unwanted strings.
Cheers and Hope it helps! I have tried this thing in many of my projects and it has always been a success for me.

Django- How to define django variable in template by javascript variable?

Is their any way to define django variable in template by javascript variable
you can do like this in your script.
<script type="text/javascript">
var a = "{{yourVariable}}";
</script>
and store it as script variable
I suppose you have to do few thing before delcare any django variable in temple by using javascript:
step 1: views.py
def XYZfunc(request, abc):
try:
some code here...
content = {'abc': abc}
return render(request, 'ProjectName/xyz_html_page.html', content)
except(ObjectDoesNotExist, KeyError, ValueError):
content = {'abc': abc}
return render(request, 'ProjectName/xyz_html_page.html', content)
step 2: urls.py (optional)
url(r'^ProjectName/xyz_htmlpage_name/(?P<abc>[A-Z]+)/$', views.XYZfunc, name="abc"),
(please note: if you are sending value through html url from views.py
then use urls.py and if value is string then (?P[A-Z]+) )
Step 3: xyz_html_page.html
<script type="text/javascript">
var u = "{{abc}}";
</script>
i hope it might help you.

How to pass a queryset from django to javascript function?

I want to pass a queryset from a view to a javascript function throught the template:
my view.py:
def myview(request):
lista=Mymodel.objects.filter(tipo=mytipo)
context_dict['lista']=lista
return render(request, 'mytemplate.html', context_dict)
my template.html:
<script>
<!--
window.onpageshow = function() {
myfunction('{{lista}}');
};
-->
</script>
my javascript.js:
function myfunction(lista) {
for (i=0; i<lista.length; i++) {
console.log(lista[i].name)
}
}
The problem is that lista become a string. I tried with JSONEncoder but i'm not sure how to use. I would like to avoid JsonResponse because I want to use that view for my template (if possible).
Edit:
There's a problem with the solution proposed in the answer:
TypeError: Python object is not JSON serializable
and the solution proposed in this link doesn't works either (can't find _meta attribute called by model_to_dict).
JSON.parse doesn't works
SyntaxError: missing ) after argument list
and the problem seem to be between one path and the other:
myfunction(JSON.parse('['/mypath/myimage.png', '/otherpath/otherimage.png', 'etc... ']'));
Also in the template you must add |safe.
Luckly I need a list of string so:
my view.py:
def myview(request):
lista=Mymodel.objects.filter(tipo=mytipo)
lista_formatted=[]
for elem in lista:
lista_formatted.append('/media/'+str(elem.myfield))
lista_formatted=json.dumps(lista_formatted)
context_dict['lista']=lista_formatted
return render(request, 'mytemplate.html', context_dict)
my template.html:
<script>
<!--
window.onpageshow = function() {
myfunction({{lista|safe}});
};
-->
</script>
change the line below
context_dict['lista']=json.dumps(lista) //note json.dumps() wraps it
Remove the quotes around here:
<script>
<!--
window.onpageshow = function() {
myfunction({{lista}});//<--quote removed!
};
-->
</script>
You need to first pass a queryset as a list of dictionary representing instances to the template. In order to do so in the views.py:
def myview(request):
lista = Mymodel.objects.filter(tipo=mytipo)
context_dict['lista'] = list(lista.values())
# Also you can instead also pass the needed parameters to 'values' function, like this:
# context_dict['lista'] = list(lista.values('field1', 'field3'))
return render(request, 'mytemplate.html', context_dict)
Then you need to define a js variable in the template and pass the value of lista to it. So in the mytemplate.html file:
<script>
window.onpageshow = function() {
myfunction({{ lista|safe }}); <!-- Don't forget to use 'safe' templatetag! -->
};
</script>
This way you don't need to use any third-party package.

Categories

Resources