Jinja, loading javascript script - flask

I have a script that overrides autocomplete
<script type="text/javascript">
$(function() {
$("#autocomplete").autocomplete({
source:function(request, response) {
$.getJSON("{{url_for('user.autocomplete')}}",{
search: request.term,
}, function(data) {
response(data.results);
});
},
minLength: 2,
}
});
})
</script>
Later in my code i have the following form
<form method=post action="{{ url_for('user.merge_user')}}">
<input name="autocomplete" type="text" id="autocomplete" class="form-control input-lg", length="20"/>
{{ form.user_name(id="autocomplete", class="form-control input-lg") }}
<input class="btn btn-default" type=submit value=Register>
</form>
The HTML input uses the script as desired but the Jinja version uses the default autocomplete method. How can I get it to use the script?

This is probably the solution you are looking for. It enables Jinja2 to load the JavaScript file before HTML is rendered.
{% block javascript %}
<script type="text/javascript">
{% include "script.js" %}
</script>
{% endblock %}
Also, a similar question can be found here.
Note that if you are using Flask with this solution (which you are), you may experience some issues related to Jinja not finding the JavaScript file on the server. IDK how to fix this; was too lazy anyways.
:3

Related

Jinja templating not working in script.js

I need to include jinja templating in element.innerHTML but jinja is not working.
Code script.js:
contentDiv.innerHTML = getContent(fragmentId);
function getContent(fragmentId) {
var pages = {
quad1: `
<form class="form-inline" method="POST" id="form1">
<h3>
<input type="number" id="quad_a1" name="input_a" class="form-control mx-2 col-1" placeholder="a">
<b>x² +</b>
<input type="number" id="quad_b1" name="input_b" class="form-control mx-2 col-1" placeholder="b">
<b>x +</b>
<input type="number" name="input_c" class="form-control mx-2 col-1" placeholder="c">
<b>=</b>
<input type="number" name="input_d" class="form-control mx-2 col-2" placeholder="Default(0)">
<button type="submit" class="btn btn-primary float-right mr-5" onclick="return empty_quad()">Solve</button>
</h3>
</form>
{{ sol }}
`,
.
.
.
};
return pages[fragmentId];
}
But the output is literally {{ sol }}, not the value of sol:
So how to access the variable sol passed through flask's render_template() in script.js?
You can't use jinja2 template in your js file.
First method: You have to use inline javascript in html file using <script></script> tag, and then you can access the sol variable by assigning it to javascript variable
<script> sol = "{{sol}}" </script> // {{sol}} should be between quotation marks
Second method: If you have seperate js file. you can make a div tag, define it's class and set it's id to {{sol}}. get the element by class name and then get it's id.
Html
<div class="myclass" id="{{sol}}" style="display:none"></div>
javascript
elem= document.getElementsByClassName("myclass") ;
console.log(elem.id) // this is the sol value.
json_script
Safely outputs a Python object as JSON, wrapped in a <script> tag, ready for use with JavaScript.
Argument: HTML “id” of the <script> tag.
For example:
{{ value|json_script:"hello-data" }}
If value is the dictionary {'hello': 'world'}, the output will be:
<script id="hello-data" type="application/json">{"hello": "world"}</script>
The resulting data can be accessed in JavaScript like this:
const value = JSON.parse(document.getElementById('hello-data').textContent);
XSS attacks are mitigated by escaping the characters “<”, “>” and “&”. For example if value is {'hello': 'world</script>&'}, the output is:
<script id="hello-data" type="application/json">{"hello": "world\\u003C/script\\u003E\\u0026amp;"}</script>
This is compatible with a strict Content Security Policy that prohibits in-page script execution. It also maintains a clean separation between passive data and executable code.
django doc

FlatPicker in Django Edit custom form showing time, only days

I have a Django app, with new template where datetimepicker works well. I created an edit template but the widget do not load automatically, so I added them. But for some reason, i do not know how to bring the datetimepicker, I can only get the datepicker.
Does anybody knows please ?
The precise line in the edit template looks like:
<div>
<input id="Restriction_Start_Date_id" type="text" name="Restriction_Start_Date" value="{{ restricted_name_obj.Restriction_Start_Date|date:'n/j/Y G:i' }}" class="form form-control datepicker" >
</div>
While on the new template I have :
<div>{{ form.Restriction_Start_Date.label_tag }}</div>
<div>
{{ form.Restriction_Start_Date.errors }}
{{ form.Restriction_Start_Date }}
</div>
Solution found, I used the CDN and the following :
<link href="https://cdn.jsdelivr.net/npm/flatpickr#4.5.2/dist/flatpickr.min.css"type="text/css" media="all" rel="stylesheet">
<div>
<input type="hidden" name="Restriction_Start_Date" required="" id="Restriction_Start_Date" fp_config="{"id": "fp_14", "picker_type": "DATETIME", "linked_to": "fp_13", "options": {"mode": "single", "dateFormat": "Y-m-d H:i:S", "altInput": true, "enableTime": true}}"class="flatpickr-input" value="{{ restricted_name_obj.Restriction_Start_Date|date:'n/j/Y G:i' }}">
</div>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/flatpickr#4.5.2/dist/flatpickr.min.js"></script>
<script type="text/javascript"src="https://cdn.jsdelivr.net/gh/monim67/django-flatpickr#1.0.0/static/js/django-flatpickr.js"></script>
(Not beautiful but it will do the job for now.

How to use django-markdownx in my view in similar way to admin?

I'm stuck using django-markdownx to automatically update page and to submit changes.
I followed this question and answer and managed to get django-markdownx working in admin, and within my view. However in my view editing the textarea does not automatically update the page.
The admin page with django-markdownx is exactly what I want, updating the textarea updates the page, but not the underlying database field until you hit save.
So I then tried to rip out the admin code into my own view.
In my view/template I have a form, textarea similar to admin one. I also included "/static/markdownx/js/markdownx.js" and set my form to mostly be similar to the admin page:
<form method="POST" action="">{% csrf_token %}
<div class="markdownx">
<textarea name="myfield" rows="10" cols="40" required="" data-markdownx-upload-urls-path="/markdownx/upload/" data-markdownx-editor-resizable="" class="markdownx-editor" id="id_myfield" data-markdownx-urls-path="/markdownx/markdownify/" data-markdownx-latency="500" data-markdownx-init="" style="transition: opacity 1s ease;">
{{ note.myfield }}
</textarea>
</div>
<div class="markdownx-preview">
{{ note.formatted_markdown|safe }}
</div>
</form>
This didn't work.
I see periodically there is requests to /markdownx/markdownify/ when you edit in admin, but not mine. I'm not sure if I should aim to do the same or just do some timed javascript page refresh and pass all the data from within my form back to my view to then re-render the page again.
I can't quite get my head around the django-markdownx documentation.
UPDATE:
The Documentation seems to suggest that a call to MarkdownX() should do the initialisation.
<script src="/static/markdownx/js/markdownx.js"></script>
...
<script type="text/javascript">
let parent = document.getElementsByClassName('markdownx');
let md = new MarkdownX( element, element.querySelector('.markdownx-editor'), element.querySelector('.markdownx-preview'));
</script>
But when I try this I get.
Uncaught ReferenceError: MarkdownX is not defined
Also I don't see any initialisation like this within the admin page.
Is there an example of using the django-markdownx in your own views similar to the usage within admin?
Thanks
LB
The following is a broken solution.
The correct method would be to use the MarkdownX's built-in Javascript, but I just can't get it to work, yet. So, I wrote my own. It may be of use to others.
In template html, include js.cookie.min.js in order to get the django csrftoken. Then a callback function which will be called when a change is made to the textarea. We then update the preview div with HTML code we received back from MarkdownX's markdownify call.
<script src="https://cdn.jsdelivr.net/npm/js-cookie#2/src/js.cookie.min.js"></script>
...
<script type="text/javascript">
function myMDFunc( elem ) {
input = elem.value;
var csrftoken = Cookies.get('csrftoken');
$.ajax(
{
type: "POST",
url: "/markdownx/markdownify/",
data: { CSRF: csrftoken, csrfmiddlewaretoken: csrftoken, content: input}
})
.done(function(data, status){
document.getElementById("markdownx-preview").innerHTML = data;
});
}
</script>
Still in the template html, in the form, call this function both for onchange and onkeyup.
<form method="POST" action=""> {% csrf_token %}
{{ note.title }}
<div class="markdownx">
<textarea onchange="myMDFunc(this)" onkeyup="myMDFunc(this)" cols="60" rows="5" name="text" >
{{ note.myfield }}
</textarea>
</div>
<div class="markdownx-preview" id="markdownx-preview">
{{ note.formatted_markdown|safe }}
</div>
<input type="submit" id="submit" name="submit">
</form>
In summary, a change to the textarea means we invoke the 'onchange' or 'onkeyup', which calls myMDFunc. Then myMDFunc does an ajax call with data which is the raw MarkDown code, the response to this call is the pretty HTML data. The callback within myMDFunc updates the preview with that pretty HTML.
It kinda works. I'm sure the real MarkdownX code will handle drag'n'drop of images and pacing the ajax calls to be nice to the server.

change event on form fields django

I got this called django form fields on a template sales.html :
<div class="center-panel">
<form method="post" action="{% url 'cost_control_app:request_update' form_sale.instance.request %}">
{% csrf_token %}
<div class="row">
{%include "partials/field.html" with field=form_sale.item %}
{%include "partials/field.html" with field=form_sale.usd_value %}
{%include "partials/field.html" with field=form_sale.exchange_rate %}
{%include "partials/field.html" with field=form_sale.euros_value %}
{%include "partials/field.html" with field=form_sale.date %}
</div>
</form>
</div>
I need that when i change the usd value field, the euros field update itself depending of the exchange rate field value and viceversa....is there a "onchange" event to call or something ??
Thanks for your help !!
What you need to do is use JavaScript, to hook into the change event of the field. Assuming you're using the normal field name and ID conventions, something like this would work (presuming you're using jQuery):
$(document).ready(
function() {
$('#id_usd_value').on('change',
function(e) {
$('#id_euros_value').val(
Math.round(
parseFloat($(this).val()) * parseFloat($('#id_exchange_rate').val()) * 100
) / 100
);
}
);
$('#id_euros_value').on('change',
function(e) {
$('#id_usd_value').val(
Math.round(
parseFloat($(this).val()) / parseFloat($('#id_exchange_rate').val()) * 100
) / 100
);
}
);
}
);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
<input id="id_usd_value">
<input id="id_exchange_rate" type="hidden" value="0.92">
<input id="id_euros_value">
</form>
This is a really crude example, using raw HTML, and making some assumptions about what your exchange-rate contains.
Solved it, upgraded to Jquery 2.1.4 and works like a charm, thanks to all.

Ajax call from django template

I have a django template which extends the base template that has code to load jquery in it. This template has a simple text box and I wanted to fetch the object through ajax.
{% extends 'base.html' %}
{% block content %}
<form id="ajaxform">
<input type="text" name="first_name" id="name" />
<input type="submit" value="Submit" />
</form>
<div id="dataDiv">
</div>
<script>
$('#ajaxform').submit(function(){
console.log('Form submitted');
$.get('{% url get_ajax_data %}', $(this).serialize(),function(data){
$('#dataDiv').text(data);
})
return false;
});
</script>
{% endblock %}
In this template, I tried to make ajax call to the get_ajax_data url and in the corresponding view I simply returned text as return HttpResponse('Ajax respose'). But this does not seem to work and the form gets submitted while I have returned false. I am not sure where I missed.
Till was on to the answer, Common practice is to initialize the submit() handler. This is done by setting it when the page is ready. Currently you have it to submit the form the regular way, it's not even registering with your javascript. To fix it you could write:
$(document).ready(function() {
$('#ajax_form').submit(fun // the rest of your code here.
});
jQuery event handlers fail silently if there's an error in them. Check for the obvious things like missing semicolons, etc. Make sure everything is valid in the event handler and it should work.