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.
Related
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.
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.
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.
I'm working on a Python package that uses Tornado to send data to the browser for visualization. In order to do this, I want the users to be able to write multiple arbitrary modules for the server to render together on a single page -- including each module's own JavaScript.
However, by default, the Tornado's UIModule class's embedded_javascript() method only appends JavaScript to <script>...</script> once per module class. I'm hoping there is a simple way to embed multiple pieces of JS, one for every UIModule (or another way to get the same effect).
Here's a minimal example of what I'm talking about:
import tornado.ioloop
import tornado.web
import tornado.template
class Element(tornado.web.UIModule):
'''
Module to add some custom JavaScript to the page.
'''
def render(self, element):
self.js_code = element.js_code
return ""
def embedded_javascript(self):
return self.js_code
class InterfaceElement(object):
'''
Object to store some custom JavaScript code.
'''
def __init__(self, js_code):
'''
Args:
js_code: Some JavaScript code in string form to add to the page.
'''
self.js_code = js_code
class MainPageHandler(tornado.web.RequestHandler):
def get(self):
elements = self.application.modules
self.render("uitest_template.html", app_name="Testing", elements=elements)
class ThisApp(tornado.web.Application):
def __init__(self, modules):
self.modules = modules
main_handler = (r'/', MainPageHandler)
#settings = {"ui_modules": {"Element": Element}}
settings = {"ui_modules": {"Element": Element},
"template_path": "ui_templates"}
super().__init__([main_handler], **settings)
# Create two objects with some custom JavaScript to render
module_1 = InterfaceElement("var a = 1;")
module_2 = InterfaceElement("var b = 2;")
app = ThisApp([module_1, module_2])
app.listen(8888)
tornado.ioloop.IOLoop.instance().start()
And the template for uitest_template.html is just
<!DOCTYPE html>
<head>
<title> Hello World </title>
</head>
<body>
{% for element in elements %}
{%module Element(element) %}
{% end %}
</body>
The rendered page then includes a <script> tag in body that is:
<script type="text/javascript">
//<![CDATA[
var b = 2;
//]]>
</script>
And what I want is:
<script type="text/javascript">
//<![CDATA[
var a = 1;
var b = 2;
//]]>
</script>
Or something like it. Any ideas?
Added - my solution
Based on the answer below, here's how I ended up handling it:
import tornado.ioloop
import tornado.web
import tornado.template
class InterfaceElement(object):
include_js = [] # List of .js files to include
js_code = '' # JavaScript string to include
def __init__(self, include_js=[], js_code=''):
self.include_js = include_js
self.js_code = js_code
class MainPageHandler(tornado.web.RequestHandler):
def get(self):
self.render("modular_template.html",
includes=self.application.include_js,
scripts=self.application.js_code)
class ThisApp(tornado.web.Application):
def __init__(self, modules):
# Extract the relevant info from modules:
self.modules = modules
self.include_js = set()
self.js_code = []
for module in self.modules:
for include_file in module.include_js:
self.include_js.add(include_file)
if module.js_code != '':
self.js_code.append(module.js_code)
main_handler = (r'/', MainPageHandler)
settings = {"template_path": "ui_templates",
"static_path": "ui_templates"}
super().__init__([main_handler], **settings)
module_1 = InterfaceElement(js_code="var a = 1;")
module_2 = InterfaceElement(include_js=["test.js"], js_code="var b = 1;")
app = ThisApp([module_1, module_2])
app.listen(8888)
tornado.ioloop.IOLoop.instance().start()
Which goes with the following template:
<!DOCTYPE html>
<head>
<title> Hello world </title>
</head>
<body>
<!-- Script includes go here -->
{% for file_name in includes %}
<script src="/static/{{ file_name }}" type="text/javascript"></script>
{% end %}
<script type="text/javascript">
// Actual script snippets go here.
{% for script in scripts %}
{% raw script %}
{% end %}
</script>
</body>
embedded_javascript and related methods are (effectively) class-level methods; they must return the same value for any instance of the class. (They're intended to be a kind of dependency-management system, so you can load a piece of javascript only on pages that include a module that needs it)
The only thing that is allowed to vary per instance is the output of render(), so to embed multiple pieces of javascript you should include the script tag in the result of your render() method.
Given HTML code such :
<!-- 2. Anchor -->
<div id="anchor">This div is the <b>#anchor</b>.</div>
<!-- 3. Template -->
<script id="tpl" type="text/template">
{{#people}}
<div><img src="{{photo}}"><b>{{family}} {{name}}</b> — {{title}}, {{place}} : {{introduction}}.</div>
{{/people}}
</script>
Given JS/Handlebars such as :
<!--4. Handlebars.js slingshot -->
//4a.function creation
var slingshot = function (url, tplId, anchor) {
$.getJSON(url, function(data) {
var template = $(tplId).html();
var stone = Handlebars.compile(template)(data);
$(anchor).append(stone);
});
}
slingshot('data.json', '#tpl', '#anchor'); // since url = 'data.json' , we can use both notations.
How to externalize the my 3. Template (#tpl) into a proper .txt text file (or other extension) ? How to load it back ? so I may use the same template into various .html webpages.
Full code : http://bl.ocks.org/hugolpz/8075193 / http://bl.ocks.org/hugolpz/raw/8075193/
Put the following template content into a file named test.handlebars
{{#people}}
<div><img src="{{photo}}">
<b>
{{family}} {{name}}
</b> — {{title}},
{{place}} : {{introduction}}.
</div>
{{/people}}
Write a function which will use the template as below
function getTemplate(name) {
if (Handlebars.templates === undefined || Handlebars.templates[name] === undefined) {
$.ajax({
url : name + ".handlebars",
success : function(data) {
if (Handlebars.templates === undefined) {
Handlebars.templates = {};
}
Handlebars.templates[name] = Handlebars.compile(data);
},
async : false
});
}
return Handlebars.templates[name];
}
In the main program you can write the below statement to insert the template contents into div with id="anchor", as shown below
var Template = getTemplate("test")
this.$("#anchor).append(Template(data));
where data is the contents of a json file or some db query output which will give you the values meant for the following attributes in json format
people, twitter, name, family, photo, title, place, introduction
I'm assuming you have already compiled your template. So you can use the technique I have described in Bootstrapping Multiple Instances of an HandlebarsJS Template Into a Page.
Hook and libs
Place this in your index.html:
<div class="hook" data-json="data/whatever.json"></div>
and the JavaScript libs
<!-- Helper to inject data-set in templates instance -->
<script src="scripts/template-loader.js"></script>
<!-- Get the (compiled) template -->
<script src="scripts/myTemplate.hbs.js"></script>
template-loader.js helper
$(function(){
'use strict';
var compiledTemplate = myApp.Templates['app/templates/myTemplate.hbs'];
$('.hook').each(function(i, h){ # h = current hook
var url = $(h).data('json'); # data-set's url
$.getJSON(url).then(function (json) { # fetch data-set
var tpl = compiledTemplate( json ); # inject data into template
$(h).html(tpl); # inflate template in page
});
});
});
Please read the complete article for further details.