Using variables in javascript and html - javascript

I would like to use a variable which I passed to the html template via flask in a javascript code. Here is an example: I have a list which I passed to the html template and I run a for loop over that list
<body>
{% for group in groups %}
<input class="group_sel" type="checkbox" id="{{ group[0] }}" name="groupstoselect[]" value="{{ group[0] }}">{{ group[0] }}
</input><br>
{% endfor %}
</body>
here I have a list (groups) and loop over that list. My question is if I want to do that loop in a jquery statement, how would that work?
thanks
carl

Server side template generates list of checkboxes with the same class .group_sel. Now on the client you can select this collection and loop over it with this code:
$('.group_sel').each(function() {
console.log( this.value );
});
Also make sure your HTML is valid, remove </input>, it should be:
{% for group in groups %}
<input class="group_sel" type="checkbox" id="{{ group[0] }}" name="groupstoselect[]" value="{{ group[0] }}"> {{ group[0] }}
<br>
{% endfor %}

Theres no big change if you just want to move the Jinja to a javascript that works in the same way as defining it in the html.
<script type="text/javascript">
var d = {{ groups }}
d.forEach(function(entry) {
console.log(entry);
});
You might have to add the |safe filter to groups. {{ groups|safe }}
The safe filter explicitly marks a string as "safe", i.e., it should not be automatically-escaped if auto-escaping is enabled. See http://jinja.pocoo.org/docs/dev/templates/#working-with-automatic-escaping

Related

Dynamic querySelector with Dynamic Jinja HTML

I have forms that are rendered dynamically based on values in a dictionary. They are given an ID based on the key value. They are all initially hidden.
<div id="subforms" style="display: none" >
{%for k, v in options.items() %}
<h3>{{k}}:</h3>
<form id= "{{k}}">
{% for option in v %}
<label>{{option}}</label>
<input type="checkbox" name="{{option}}_enabled">
{% endfor %}
</form>
{% endfor %}
</div>
I now create an input list with those same keys:
<form action="/action_page.php">
<input list="tables" id="tablelist" >
<datalist id="tables">
{% for key in options.keys() %}
<option value={{key}}>
{% endfor %}
</datalist>
</form>
Last I have Javascript used to listen to the tablelist element and select a form based on the inputlist's value.
const tables = document.getElementById("tablelist")
const subform_block = document.getElementById("subform_display")
const forms = document.getElementById("subforms")
tables.oninput = () => {
let form =
forms.querySelector('form[id="${tables.value}"]');
if(form){
subform_block.innerHTML = form.outerHTML;
}
else {
subform_block.innerHTML = "not found";
}
}
The querySelector is not working. I confirmed that the HTML is rendered correctly and the IDs are consistent, but my querySelector is unable to find any of the forms. What is wrong?
Changed:
let form = forms.querySelector('form[id="${tables.value}"]');
to:
document.querySelector('form[id=' + tables.value + ']');
And it works. Not sure why ${tables.value} wasn't recognized properly

Django referencing Javascript variable in server side template code

I have a page that adds textboxes dynamically, and on the dynamically added text boxes, I want to access the relevant context variable.
To do so, I somehow need to use the 'i' variable inside the javascript code/template code to reference it's value in the context.
Here's my javascript code where I need to use 'i' as an index for a context list:
<script>
var i = 2
function add_field()
{
var table = document.getElementById("tbl_location").getElementsByTagName('tbody')[0];
var input_name = document.createElement("th")
input_name.appendChild(document.createTextNode("S/N " + i))
var input_tb = document.createElement("td")
var input = document.createElement('input');
input.setAttribute("name", "sn" + i);
{% if curr_sn.i %}
input.setAttribute("value", {{ curr_sn.i }});
{% endif %}
input_tb.appendChild(input)
var input_row = document.createElement("tr")
input_row.appendChild(input_name)
input_row.appendChild(input_tb)
table.appendChild(input_row);
i++;
}
The specific lines are:
{% if curr_sn.i %}
input.setAttribute("value", {{ curr_sn.i }});
{% endif %}
Where 'i' is a javascript veriable, and curr_sn is a list the python code gives as a context.
The html part where I need to use 'i':
{% for i in max_board_list %}
{% if curr_sn.i %}
<tr>
<th>S/N {{ i }}</th>
<td><input type="text" name="sn{{ i }}" value="{{ curr_sn.i }}"></td>
</tr>
{% endif %}
{% endfor %}
Here 'i' is generated by a for loop, but I still need to access the same list.
How can I do this in both parts of code? All I could find the the opposite way which already works for me (using django template in javascript code).
Thanks
EDIT: for javascript side i found a solution (since I noticed that anyway my code is redundant and tries to do similar things in js&html). For the javascript part I use:
{% if curr_sn|length > 1 %}
i = {{ curr_sn|length }}
{% endif %}
Just to keep counting from the current number of boards.
Now I need to solve the html parts to display the saved boards in the context variable curr_sn
Found a solution for the html part as well.
I just use custom filters to do the checking.
I've registered two filters:
#register.filter(name='is_in')
def is_in(index, list):
if list is None:
return False
try:
list[int(index)]
return True
except:
return False
#register.filter(name='get_value')
def get_value(index, list):
if list is None:
return False
try:
return list[int(index)]
except:
return None
And in the HTML part I use the following:
{% for i in max_board_list %}
{% if i|is_in:curr_sn %}
<tr>
<th>S/N {{ i }}</th>
<td><input type="text" name="sn{{ i }}" value="{{ i|get_value:curr_sn }}"></td>
</tr>
{% endif %}
{% endfor %}
Hope this will help for others with the same problem.

jQuery datetimepicker- unable to select date from next year

I am working on a Python/ Django project, and one of the forms on a webpage has a datetimepicker field on which the user can select a date/ time from the drop-down that appears when the field is selected.
The problem that I currently have is that although the calendar displays a full month at a time, and the user can move through months/ years at a time by selecting next/ previous month, or choosing the year from a drop down inside the calendar, if they move to a month beyond the end of this year, then none of the dates are available for selection.
Having Google'd datetimepicker, it seems that this is a jQuery function, and I want to make sure that there is no value for its maxDate attribute- I've looked through jquery.datetimepicker.full.js, and although it's referenced there, it doesn't see to be given a value at all... so I can't see why this field is not allowing me to select a date beyond the end of this year... anyone have any ideas?
The view that is rendering this page is:
def concept(request, project_id):
project = Project.objects.prefetch_related('budget_versions').get(id=project_id)
deposit = Deposit.objects.get_or_create(project=project)[0]
presentations = project.budget_versions.select_related('meeting').prefetch_related('budget_items', 'cci_items', 'presenters').filter(version_number__isnull=False).annotate(vn=F('version_number') * -1).order_by('presentation_date', 'created', '-vn')
end_details = EndDetails.objects.get_or_create(project=project)[0]
presentation_formset = BudgetPresentationFormset(prefix="presentations", instance=project, queryset=presentations)
drawing_formset = DrawingUploadFormset(prefix="drawings", queryset=Drawing.objects.filter(budget__in=presentations).order_by('budget__presentation_date', 'budget__created'))
context = {
'project': project,
'presentations': presentations,
'presentation_formset': presentation_formset,
'drawing_formset': drawing_formset,
'deposit_form': DepositInfoForm(instance=deposit),
'ended_form': EndDetailsForm(instance=end_details),
'budget_notes_form': BudgetNotesForm(instance=project.budget_overview),
}
return render(request, 'projects/concept.html', context)
and the Django that is displaying the form on which the 'date' field is displayed is:
{% if not forloop.last and presentation_form.instance.budget_items.count %}
<tr class="split-rows">
<td colspan="3">Exc VAT {% if not presentation_form.instance.current_marker %}{{presentation_form.instance.grand_total_exc_vat|money:'£'}}{% else %}{{project.budget_overview.updated_exc_vat|money:'£'}}{% endif %}</td>
<td colspan="3">Inc VAT {% if not presentation_form.instance.current_marker %}{{presentation_form.instance.grand_total_inc_vat|money:'£'}}{% else %}{{project.budget_overview.updated_inc_vat|money:'£'}}{% endif %}</td>
</tr>
{% endif %}
<tr>
{% for hidden in presentation_form.hidden_fields %}
<td class="hidden">{{ hidden }}</td>
{% endfor %}
</tr>
{% for field in presentation_form.visible_fields %}
<tr class="split-rows">
{% if not field.name == 'pdf_package_dep' %}
<td colspan="6"><label>{{field.label}}</label></td>
{% endif %}
</tr>
<tr class="split-rows">
<td colspan="6">
{% if not field.name == 'pdf_package_dep' %}
{% if field.name == 'presentation_date' %}
{% with presentation_form.instance.meeting as meeting %}
{% include "projects/includes/meeting_bit.html" with employee=request.user.employee meeting=meeting UID=presentation_form.instance.id %}
{% endwith %}
{# <a class="ical_trigger button" data-view-url="{% url 'events:add_to_cal' %}" {% if not field.value %}style="display:none"{% endif %}>Add to calendar</a> #}
{% else %}
{{field}}
{% endif %}
{% endif %}
</td>
</tr>
{% endfor %}
Edit
It would appear that what's actually displaying the calendar is the HTML file included by the line:
{% include "projects/includes/meeting_bit.html" with employee=request.user.employee meeting=meeting UID=presentation_form.instance.id %}
The meeting_bit.html file has the following code:
{% if meeting and meeting.event_creator and meeting.event_creator != employee %}
<table>
<tr>
<td>
{{meeting.date|date:"d/m/Y H:i"}}<br>
</td>
<td rowspan="2"><a class="change_event_organiser" data-view-url="{% url 'events:change_event_creator' meeting.id %}" class="button">Edit</a></td>
</tr>
<tr>
<td class="text-sm">
Organised by {{meeting.event_creator}}
</td>
</tr>
</table>
{% else %}
<div id="cal_{{field.name}}_{{UID}}">
{{field}}
<a class="ical_trigger button" data-view-url="{% url 'events:add_to_cal' %}" {% if not field.value %}style="display:none"{% endif %}>
{% if meeting.event_id %}Update calendar event{% else %}Add to calendar{% endif %}
</a>
</div>
{% endif %}
I can see when I 'inspect' the date field of the form in the browser, that it is in a div which has an ID in the format cal_{{field.name}}_{{UID}}, so I know that this is where the calendar is initialised/ displayed... But I can't see anything that is restricting the available options for selection to dates from this year only... why can't I select a date from next year, or any other year in the future?

Pass an array of a twig for a jQuery

I have a block on my twig writing a table from a variable received from controller
{% block foot_informations %}
{% if ads is not empty %}
<div class="panel-foot-information row">
<table id="ads">
<thead>
<tr>
<th>Departure</th>
<th>Destination</th>
</tr>
</thead>
<tbody>
{% for ad in ads %}
<tr class="ad-tr">
<td>{{ ad.departure }}</td>
<td>{{ ad.packageType }}</td>
<td>{{ ad.transportation }}</td>
{# <td>{{ ad.date }}</td> #}
<td>select</td>
<td class="hidden"><input type="hidden" id="idLat" value="{{ ad.departureLatitude }}"/></td>
<td class="hidden"><input type="hidden" id="idLong" value="{{ ad.departureLongitude }}"/></td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endif %}
{% endblock %}
I would like to get this variable month in JQuery to manipulation it and then rewrite my table
to catch it saw something like this: var ads = {{ ads|json_encode() }};
My idea is in a evnto of button to click to change the value of the array and reconstruct the table someone help me?
$('#my_button').click(function () {
alert(ads);
$.each(ads, function(){
alert($(this));
//filter by type package
});
//rewrite table
});
First of all I would suggest that you don't mix two strategies.
is generating views serverside, what you obviously do with the twig templates.
is passing raw data (with AJAX or like your example with the json_encoded array parsed into a JS Object), and then generating the table with JS DOM manipulation.
But that's my opinion about this part.
If you choose for Option 1 you could add/remove classes in your $.each filter-like callback for the table rows you want to hide / show.
And then write something like this in your stylesheet
tr.filtered {
display: none;
}
Alternative: extend your table body like this:
<tbody>
{% for ad in ads %}
<tr data-ad-id="{{ ad.id }}" class="ad-tr">
<td>{{ ad.departure }}</td>
{# all the other td's #}
</tr>
{% endfor %}
</tbody>
And you Clickhandler:
$('#my_button').click(function() {
//alert(ads);
$.each(ads, function(index, ad) {
if (ad.packageType == 'some_package_type') {
$('table#ads tr[data-ad-id=' + ad.id + ']').hide();
}
});
// rewrite table
// Perhaps there is no need for anymore
});
EDIT:
If you have a javascripts block in your base template, you could do this to expose an ads array to the global JS scope (just like you said in the question, about what you have seen):
{% block javascripts %}
{{ parent() }}
<script>
var ads = {{ ads|json_encode() }};
</script>
{% endblock %}

Show button in Django template only when the file is selected through check box?

I am getting the check box dynamically in Django template like this:
<td><input type="checkbox" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" /></td>
<td><label for="choice{{ forloop.counter }}">{{ choice.file_name }}</label></td>
There's a unshare button like this:
<button>Unshare</button>
I want to show the Unshare button only when the user clicks on check-box.
Firstly add some more id's to your template so that you can identify elements.
<table id="choices">
{% for choice in choices %}
<td><input type="checkbox" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.id }}" /></td>
<td><label for="choice{{ forloop.counter }}">{{ choice.file_name }}</label></td>
{% endfor %}
</table>
Then give the button an id and an inline style -
<button id="unshare_button" style="display: none;">Unshare</button>
Then use the following javascript (this shows the button as soon as any one of the
checkboxes is clicked - it doesn't hide the button if they're unchecked).
var choices_table = document.getElementByID('choices');
var checkboxes = choices_table.getElementsByTagName('input');
var unshare_button = document.getElementByID('unshare_button');
for (var i = checkboxes.length; i > 0; i--) {
checkboxes[i].addEventListener('click', function() {
unshare_button.style.display = 'inline';
}
}
I'm afraid I haven't checked this code, but it should give you an idea.

Categories

Resources