How do i create and use variables in django - javascript

New to Django and its templates.
I'm trying to set a variable given a specific situation, and that part I think ill be able to do, the code below isn't the exact conditions its just there as a demo. The part im stuck on is how do i create a variable name, and then use that name variable elsewhere. Such as within a div or within a method or anywhere else within the html file, and withing different <Script> tags to run methods and for really any purpose.
demo scenario :
{% for row in table.rows %}
{% if row == 2 %}
{% var name = row.name %}
{% endif %}
{% endfor %}
{% if name %}
<div>{{name}}</div>
{% endif %}
my actual code Im trying to implement:
<script type="text/javascript">
function map_init_basic(map, options) {
var markerClusters = L.markerClusterGroup({ chunkedLoading: true });
{% for row in table.rows %}
var x = "{{ row.cells.x }}"
var y = {{ row.cells.y }}
var m = L.marker([y, x])
m.bindPopup("{{row.cells.first_name}} {{row.cells.last_name}} <br>{{row.cells.chgd_add}}");
m.on("click" , ()=>{
//console.log(`${first_name} ${last_name}`)
{% var first_name = {{row.cells.first_name}} %}
})
//changed row.cells.chgd_add to row.cells.Chgd_add to make sure its matching the table
markerClusters.addLayer(m);
{% endfor %}
markerClusters.addTo(map);
}
{% if first_name %}
console.log("{{first_name}}");
{% endif %}
</script>

Django templates are intended to render html but you are trying to render javascript. It can work but the way you are trying to do it is not a good practice; very soon you won't be able to maintain your code.
If you want to pass data directly from python/django to javascript, an accceptable way to do so is to put the data in a dictionary, translate it to a json string and have it set to a var in your javascript.
in a view:
data = dumps(some_dictionary)
return render(request, 'main/template.html', {'data': data})
in the template:
<script>
var data = JSON.parse("{{data|escapejs}}");
</script>
https://docs.djangoproject.com/fr/3.1/ref/templates/builtins/#escapejs
Alternative: You can use django to generate a widget with data attributes and have a javascript operating on this widget and do whaterever needs to be done.

Related

building a array/object in a nunjucks loops

I have the following in my nunjucks file,
{% set inProgressJobs = [] %}
{% for job in jobs %}
{% set inProgressJobs = (setProgressJobs.push([
{
text: "<b>{{ job.jobTitle}}</b>"
}
]), inProgressJobs) %}
When I use this in by view I would expect to see Web Designer but I am actually seeing {{ job.jobTitle }} how I interprolate my var into the text attribute?
You try to coding inside a template. It's a possible (see below) but out of template ideology. Try to put necessary logic to filters and global functions.
const nunjucks = require('nunjucks');
const env = nunjucks.configure();
env.addFilter('print', console.log); // for debug
const html = env.renderString(`
{% set arr = [] %}
{% for i in range(1, 10) %}
{{ '' if arr.push(i) }} {# arr.push always returns non-zero so result will be '' #}
{% endfor %}
{{ arr | print }} {# print arr to console #}
`);
// console.log(html); // html is a pack of spaces and tabs

Adding python variables to jinja counter

I want to add the python variables from flask in the jinja template
Suppose 'a' is a python variable(a list of int values) brought into the jinja template using render_template function from flask :
{%set count = 0%}
{%for element in a%}
{%set count = count + element%}
{%endfor%}
{{ count }}
The value of 'count' should be updated but it still prints 0 on the screen
Can anyone help me?
In the most recent versions, due to scoping rules, your version doesn't work.
Instead, you could do something like this:
{% set count = namespace(value=0) %}
{% for element in a %}
{% set count.value = count.value + 1 %}
{% endfor %}
{{ count }}

How to retrieve Django model id from admin page via javascript

Suppose I have a Django model like this one.
class Car(models.Model):
speed = models.IntegerField()
color = models.CharField(max_length=120)
I registered it in admin via
admin.site.register(Car)
I want to add custom JS button for admin site object view, which will alert value of a color of an instance of a Car model. So when I press it I get something like "The car with id 13 is red"
How can I get id of an object and value of a color field via JavaScript?
You have to extend change_form.html template for you app (https://docs.djangoproject.com/en/2.2/ref/contrib/admin/#overriding-vs-replacing-an-admin-template)
For example I have store app and inside models.py I've put Car model.
Then inside store/templates/admin/store/change_form.html I've put this template:
{% extends "admin/change_form.html" %}
{% load i18n admin_urls %}
{% block content %}
{{ block.super }}
<script>
const object = {
pk: {{ original.pk }},
color: '{{ original.color }}',
};
</script>
{% endblock %}
{% block object-tools-items %}
{{ block.super }}
<li>
My button
<script>
const button = document.getElementById('my-button');
button.addEventListener('click', function() {
alert(`The car with ${object.pk} is ${object.color}`);
});
</script>
</li>
{% endblock %}
Admin view:

javascript - dry - nested if statement

I am new to coding, but have been reading about DRY - Don't Repeat Yourself.
I have a JavaScript if/else statement that does not fit the DRY approach, but I am unable to workout how to write the JavaScript if/else statement so that the contents are not repeated.
I am hoping some one smarter than me can show me.
Here is my code:
{% if user.get_profile.subscription_category == '00' %}
$('#id_name_details_prefix_title').addClass('kmw-disabled');
$('#id_name_details_first_name').addClass('kmw-disabled');
$('#id_name_details_middle_name').addClass('kmw-disabled');
$('#id_name_details_last_name').addClass('kmw-disabled');
$('#id_name_details_suffix_title').addClass('kmw-disabled');
{% else %}
{% if user.get_profile.display_virtual_keyboard %}
$('#id_name_details_prefix_title').removeClass('kmw-disabled');
$('#id_name_details_first_name').removeClass('kmw-disabled');
$('#id_name_details_middle_name').removeClass('kmw-disabled');
$('#id_name_details_last_name').removeClass('kmw-disabled');
$('#id_name_details_suffix_title').removeClass('kmw-disabled');
{% else %}
$('#id_name_details_prefix_title').addClass('kmw-disabled');
$('#id_name_details_first_name').addClass('kmw-disabled');
$('#id_name_details_middle_name').addClass('kmw-disabled');
$('#id_name_details_last_name').addClass('kmw-disabled');
$('#id_name_details_suffix_title').addClass('kmw-disabled');
{% endif %}
{% endif %}
The contents of the 1st if are repeated in the else of the 2nd if statement - I am hoping that I only have to write the repeated contents once.
You can put your selectors in an array
var selectors = [#id_name_details_prefix_title', '#id_name_details_first_name' ...];
and then add/remove class
$(selectors.join(',')).addClass('kmw-disabled')
Break it up into functions that isolate what's going on.
{% if something %}
functionThathAddsClass();
{% else %}
{% if something_else %}
functionThatRemovesClass();
{% else %}
functionThathAddsClass();
{% endif %}
{% endif %}
You will run into the problem of creating two global functions in this case, but that's a different issue.
I like to make, what I personally call, CSS Guards.
A CSS Guard is basically just an object that has functions that pokes and prods at the DOM.
var NameDetailsGuard = {
functionThathAddsClass = function () {
$('#id_name_details_prefix_title').addClass('kmw-disabled');
$('#id_name_details_first_name').addClass('kmw-disabled');
},
functionThatRemovesClass = function () {
$('#id_name_details_prefix_title').removeClass('kmw-disabled');
$('#id_name_details_first_name').removeClass('kmw-disabled');
}
};
and you use it like this
NameDetailsGuard.functionThatAddsClass();
An added benefit to this is that if you expand on this concept you can start doing simpler DOM node caching within this object so that instead of querying for the selector everytime you'll retain a reference to it and manipulate that.
You can add some class to needed elements (in HTML markup) and select by that class.
For example, add category-zero and virtual-keyboard classes and use following:
{% if user.get_profile.subscription_category == '00' %}
$('.category-zero').addClass('kmw-disabled');
{% else %}
{% if user.get_profile.display_virtual_keyboard %}
$('.virtual-keyboard').removeClass('kmw-disabled');
{% else %}
$('.virtual-keyboard').addClass('kmw-disabled');
{% endif %}
{% endif %}

New forms - embedding a collection of forms - Symfony2

I'm doing the same as explained here: http://symfony.com/doc/current/cookbook/form/form_collections.html
But in my case I want to add new "tags" not manually with clicking on a link, but automatically. I give to my template an array with items and for each of this items I want to add a new form - the number of items should be equal to the number of forms.
If it's possible, I'd prefer a solution like this:
{% for i in items %}
{{ i.name }} {{ form_widget(form.tags[loop.index0].name) }}
{% endfor %}
But how to automatically create objects in the controller, too? It tells me that there is no obeject with index=1, and yes - there isn't, but isn't there a way to create them automatically and not need to create for example 10 empty objects of the same kind in my controller? :(
Another thing I was thinking was something like this:
{% for i in items %}
<ul class="orders" data-prototype="{{ form_widget(form.orders.vars.prototype)|e }}">
{{ i.name }} and here should be a field from the form, for example tag.name
</ul>
{% endfor %}
I suggest that the js given in the cookbook should be changed to do this, but I'm not good in js and my tries didn't do the job.
I tried putting this in the loop:
<script>
addTagForm(collectionHolder);
</script>
and this in a .js file:
var collectionHolder = $('ul.orders');
jQuery(document).ready(function() {
collectionHolder.data('index', collectionHolder.find(':input').length);
function addTagForm(collectionHolder) {
var prototype = collectionHolder.data('prototype');
var index = collectionHolder.data('index');
var newForm = prototype.replace(/__name__/g, index);
collectionHolder.data('index', index + 1);
var $newFormLi = $('<li></li>').append(newForm);
}
});
Assuming that your main class has addTag($tag) method, you can add different 'new' tags to it.
In class Task
public function addTag($tag){
$this->tags[]=$tag;
return $this;
}
In your Controller (assuming 10 tags here)
$task=new Task();
for($i=0;i<10;i++){
$task->addTag(new Tag());
}
$form->setData($task);
In your view
{% for tag in form.tags %}
<ul class="orders">
<li>{{ form_widget(tag.name) }}</li>
</ul>
{% endfor %}
If you don't need the manually click, you can remove the JavaScript part.

Categories

Resources