Using django variables in Javascript - javascript

My model lop is contains a list of programs which I use for varying purposes. I want to use the name field as an argument for a javascript function.
I modified some of my lops so the modified versions have a "ver2" at the end of its name. What the Javascript function does is that it checks for the suffix "ver2" of the program. The javascript was originally found from here.
I read some similar questions and one of them said that I need to serialize the object
EDIT: Expanded view of views.py, Javascript console started working and now is included.
In my views.py (UPDATED)
from django.core import serializers
.
.
.
.
def loppage(request):
jsondata = serializers.serialize('json', lop.objects.all(),fields=('name'));
## get programs
data = []
types = Type.objects.all()
for type in types:
data.append([type.title, type.script_set.all()])
context = {'lop': Lop.objects.all(), 'cat': data, 'jsondata':jsondata}
## render list
return render(request, 'loppage.html', context)
In my templates file:
Javascript/HTML (loppage.html):
<script>
function endsWithsuffix(progname, suffix) {
return progname.indexOf(suffix, progname.length - suffix.length) !== -1;}
</script>
.
.
.
.
{% for lop in type %}
<p id="Options"><i>{{lop.options}}</i></p>
<p id="Id">{{lop.name}}</p>
<script type="text/javascript">
if (endsWithsuffix({{jsondata}}, 'ver2')) { //This I've tried with and without quotation marks, and with lop.name with and without quotation marks
document.getElementById('Options').style.visibility = 'visible';
document.getElementById('Id').style.visibility = 'visible';
}
else {
document.getElementById('Options').style.visibility = 'hidden';
document.getElementById('Id').style.visibility = 'hidden';
}
</script>
{% endfor %}
But for whatever reason, the script doesn't seem to load (it loads as if the script wasn't even though).
As wardk suggested, I have now included my Javascript console which can be seen here
SyntaxError: invalid property id loppage:56:28
It's a long repetition of this same error on the same line as shown below
Debugger console highlights
if (endsWithsuffix([{"pk": 2, "model": "programs.lop",
I've been working on this way longer than I should but I can't get anywhere with it. Help.

You're applying endsWithSuffix on a json representation of lop.objects.all(). Shouldn't you test endsWithSuffix for {{lop.name}} instead?

Related

How to import data from django.models, to use in javascript?

I am trying to import a python dictionary from moodels and manipulate/print it's properties in Javascript. However nothing seems to print out and I don't receive any error warnings.
Views.py
from chesssite.models import Chess_board
import json
def chess(request):
board = Chess_board()
data = json.dumps(board.rep)
return render(request, 'home.html', {'board': data})
Here board.rep is a python dictionary {"0a":0, "0b":0, "0c":"K0"} - basically a chess board
home.html
<html>
<body>
{% block content %}
<script>
for (x in {{board}}) {
document.write(x)
}
</script>
{% endblock %}
</body>
</html>
I also would very much appreciate some debugging tips!
Thanks in advance, Alex
Django defaults to escaping things as HTML, and that will make " into #quot;. Try changing {{board}} into {{board|safe}} to prevent the html escaping. Alternatively, in the view you can wrap the string in mark_safe() which is in django.utils.safestring to indicate that the string shouldn't be escaped.
To transfer data between django and javascript, dump data in django view and load in a javascript variable. Try to avoid django interpolation with javascript language constructs. It is unsafe, error prone, and can cause complexities.
in view
data = json.dumps(board.rep)
in template
const data = JSON.parse('{{ data|safe }}')
// use normal javascript here. 'data' is a javascript array
for (let x of data) {
document.write(x)
}

How to inject JavaScript variable in a Django template filter

I have a Django template filter to retrieve dictionary items based on the key passed.
{% with data=dict_data|get_data:key %}
I have separately made a template_tag.py file which returns those items.
def get_domain_data(dictionary, key):
p = ast.literal_eval(dictionary)
return p[key]
# data being returned successfully
The issue is in passing the dynamic value of the key in the filter function.
<script>
var key_val = $('#input_id').val();
'{% with data=dict_data|get_domain_data:"'+key_val+'" %}'; //encountering error here
// rest of the code
'{% endwith %}';
</script>
If I hardcode a string value the entire operation works, but I am unable to use the JavaScript variable within the Django {% filter %} function.
As mentionned by Matt Ellen in a comment, the template code is executed on the server, then the generated result is sent to the browser which interprets the javascript parts - so this just can not work this way.
If your data dict is small enough and doesn't depend on javascipt user interactions (ie the javascript only reads it), then the solution is to serialize it to json (in the view itself or using a template filter - one might already exists FWIW), bind it to a javascript variable (in the template) and then let the javascript code use it as just any js object, ie (assuming a "jsonify" template filter):
<script>
var data_dict = {% data_dict|jsonify %};
function do_something() {
var key_val = $('#input_id').val();
var data = data_dict[key_val];
// rest of the code
}
// and you'll probably want to bind do_something to
// some js event handler
</script>
There is a similar issue at Get javascript variable's value in Django url template tag
Providing arg1 can be numeric and the reversed url doesn't contain other instances of the string /12345/ then you can use,
var url_mask = "{% url 'someview' arg1=12345 %}".replace(/12345/, tmp.toString());

Pass variables from controller to javascript function in Fat-Free Framework

I have some values on my controller that I want to pass to a javascript function in the view page.
In the controller, I have:
$f3->set('value', $value);
I can access the value on the view with {{#value}}, but how do I use(access) that value inside a javascript function on the view page??
<script type="text/javascript">
var value = XXX; //XXX in the {{#value}}, how do i access it in here???
</script>
It depends on the content stored inside $value.
If it's a basic string with no single/double quote inside, then the following code will work:
<script>
var value='{{ #value }}';
</script>
If it's an integer, the following code will work:
<script>
var value={{ #value }};
</script>
... although your IDE will probably report a syntax error.
If it's a float, the following code will work:
<script>
var value={{ str_replace(',', '.', #value) }};
</script>
... and your IDE will also probably report a syntax error. NB: the str_replace is for non-English locales that have decimal separator set to comma.
For all the rest (strings including quotes or arrays), you should convert your data to JSON, using one of the following techniques:
Technique 1:
Convert data to JSON and dump it to a JS object.
// controller.php (JSON encode)
$f3->set('data',json_encode($data));
<!-- template.html -->
<script>
var data={{ #data | raw }};
</script>
Pros: easy to use.
Cons: your IDE will report a syntax error + extra call to raw.
Technique 2:
Convert data to JSON, dump it to a JS string and parse it.
// controller.php (JSON encode + escape double quotes)
$f3->set('data',str_replace('\\u0022','\\\\u0022',
json_encode($data,JSON_HEX_APOS|JSON_HEX_QUOT)));
<!-- template.html -->
<script>
var data=JSON.parse('{{ #data | raw }}');
</script>
Cons: less easy to use + extra call to raw.
Pros: your IDE will not report any syntax error.
Technique 2bis:
Embed technique 2 in a F3 template filter.
// index.php
$tpl=Template::instance();
$tpl->filter('safejson',function($data){
$raw=\View::instance()->raw($data);
return str_replace('\\u0022','\\\\u0022',
json_encode($raw,JSON_HEX_APOS|JSON_HEX_QUOT));
});
<!-- template.html -->
<script>
var data=JSON.parse('{{ #data | safejson }}');
</script>
Pros: easy to use + your IDE will not report any syntax error.
Cons: extra call to raw.
Technique 3:
Convert data to JSON and embed it inside a DOM data- attribute.
// controller.php (JSON encode)
$f3->set('data',json_encode($data));
<!-- template.html -->
<div id="foo" data-json="{{ #data }}"></div>
<script>
var data=JSON.parse(document.getElementById('foo').dataset.json);
</script>
Pros: easy to use + your IDE will not report any syntax error + no extra call to raw.
I went a bit lazier than that.
I have my data in a dictionary file (F3). I load it in an input field at the bottom of my page and assign value via templating. I use Jquery (plain JS could be used to) to retrieve value.
Ex:
Dict data
'prf_conf'=>' Update your profile'
In my profile.html
`< input type = 'hidden' id ='prf_conf' value='{{#prf_conf}}' >`
//this loads data in whatever language on my page
JS
Confirm button text: (i used jquery-confirm.min.js in this example)
$.confirm({ title: $('#prf_conf').value()
… bit of gymnastic but worked well. No IDE issue…

set twig variable from json array

As twig renders prior to any javascript, I'm running into what feels like a minor problem.
I need to set a variable in twig that I receive from JSON array, but I'm running into some problems, and I feel like this should be simple.
The data is fed to twig through symfony through a json array, and renders different messages depending on one element in the array; this part works without trouble.
I am able to print the output to the twig file; that works fine. The problem is that I'm having a hard time setting this to a twig variable so that I can use it in a few places.
This works fine:
$('.id').html(items[0].id);
and prints out to the twig here correctly:
<div class="id"></div>
I tried to do do something like this:
{% set requestid = '<div class="id"></div>' %}
{{ requestid }}
But as expected this simply rendered the HTML without the value.
I've been attempting to do something like this:
In the twig I have this:
{% set requestid = "request_holder" %}
{{ requestid }}
And in the jquery I have something like this:
var reqid = items[0].id;
reqid.replace("request_holder",reqid);
I also attempted something like this
var request_id = items[0].id;
window.location = request_id.replace("request_holder",request_id)
I feel like I'm missing a small piece.
**Edit for clarity **
The JSON array is being parsed by jquery.
I have the value of items[0].id
Additional edit here - to make it clear that I was confused: cleaning up a little so as not to send future readers down the wrong path
I believe[d] that the variable needs to be assigned in the javascript because the twig, which is php, is generated prior to the javascript.
I have been attempting to generate the twig in the javascript to no avail.
Here's what I have been attempting:
var requestitem = items[0].id;
$('.id').html("{% set requestId = " + requestitem + " %} <br/> {{ requestId }}");
This defines requestId as a string and is only returning + requestitem + onto the page.
When I attempt this (without the quotations)
var requestitem = items[0].id;
$('.id').html("{% set requestId = requestitem %} <br/> {{ requestId }}");
The twig does not recognize requestitem at all
I have attempted quoting out the twig brackets (e.g. "{" + "%" etc) but this of course only prints them onto the page and does not interpret them.
Twig processes on the server side. It takes variables and renders them as HTML and text. What gets displayed in the browser is just HTML / text / and Javascript. So your set requestid = "request_holder" and {{ requestid}} are just turned to text before they get to the browser.
After that, you have HTML and text on the front end which Javascript can interact with. If you need this id to change on the front end, it needs to be done in Javascript.
What are you using the id to do?
Thanks to the hint from ASOlivieri, I was able to realize what I was doing wrong. I'm putting this here in case anyone comes across this. I was simply looking for a way to create a variable and make it reusable (I didn't go into details as that seemed extraneous).
The data was only available in the JSON array, so any attempt to write it to a twig file would fail, quite simply because it had already been converted to HTML, so I was forced to find another solution,
I was able to keep the variable in a javascript as I had it before
var request_item = items[0].id;
As my original goal was to get the value to update the application through php, I simply needed to use this variable in an AJAX call, and pass it through the path I had wanted to use in twig. Here's a brief summary:
$('#mark-received').click(function()
{
var requestURL = "{{ path('my_path') }}";
jQuery.ajax({
url: requestURL,
type: 'GET',
data: {'id' : request_item},
success: function success(data, text, xhr){
$('#mark-received').addClass('hidden');
$('#received-canceled').removeClass('hidden');
$('header > .alerts').append( $('<div>Success Message</div>').addClass('alert alert-success'));
},
error: function error( xhr, status, err){
$('header > .alerts').append( $('<div>There is a problem. <div class="close">x</div></div>', err).addClass('alert alert-danger'));
}
})
});

FOR loop over a Django model in a JS script

I just started a web app using Django and HTML/Javascript templates.
My Django spot app contains a Spot model that is sent to a HTML template - to be used with the Google Map Api. I've encountered a problem when looping over the variable spots containing Spot.objects.all().
It seems the problem comes from the way I send the data to the HMTL file.
----------------------------------------- Spot Django-app : models.py --------------------------------------------
class Spot(models.Model):
idn = models.IntegerField(unique = True)
name = models.CharField(max_length = 200)
longitude = models.FloatField()
latitude = models.FloatField()
------------------------------------------------- HTML / JS -----------------------------------------------
<script type="text/javascript">
var IDs = []
var names = []
var lat = []
var lng = []
{ % for spot in spots % }
IDS.push( {{spot.idn}} );
names.push( {{spot.name}} );
lat.push( {{spot.latitude}} );
lng.push( {{spot.longitude}} );
{ % endfor % }
Then, the lists do not contain any data that can be used afterwards. Worse, the HTML file does not work if the names.push( {{spot.name}} ) is un-commented.
----------------------------------------- Spot Django-app : views.py --------------------------------------------
from spots.models import Spot
def index(request):
return render(request, 'index.html', {'spots':Spot.objects.all()})
Thanks to the other stackoverflow questions (listed below), I also tried to serialize the Spot.objects.all() either with django.core.serializers.serialize("json", Spot.objects.all() ) or by creating my own serializer (thanks to Django_REST). The problem remains the same. So is the problem in the way I parse my data with JS?
I've look the following link :
Returning JSON array from a Django view to a template
django for loop in a .html template page (newbie)
Django FOR LOOP in JavaScript
with no success. So if the answer is included or related to these topics, would you mind explaining me something I've been working around for days ...
EDIT:
The problem was plural:
Serializing the data (or not ; I did not for now but everyone who answered agreed to say that it's better to)
Adding the quotes from {{ spot.name }} to '{{ spot.name }}', only to non Integer/Float models (i.e. only the models.CharFields fields)
Google Maps Api may return errors for some (longitude, latitude) tuples even if they are well-defined
Django will not recognize those template tags because you have spaces between the brace and the percent. So, there is no looping being done at all. You need to write them in the correct format:
{% for spot in spots %}
...
{% endfor %}
Once you do that, you'll start getting all sorts of JS syntax errors because you have not wrapped any of your data in quotes. But, as the comments say, doing this as JSON would be much better.
Even that I think that serializing your data into Json is much better idea. Your javascript code does not work because e.g. {{ spot.name }} will render raw string so for javascript to understand it you need to put it in quotes (and of course semicolon after each line).
names.push('{{spot.name}}');

Categories