change event on form fields django - 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.

Related

Django ChoiceField RadioSelect widget in form, test whitch element selected in template

I have 2 radio buttons in a ChoiceField and I would like to display some parts of the template, depending of witch radio button is selected.
Following :
form.py
class CtdForm(forms.Form):
protocol_name = forms.CharField(max_length=100)
rb = forms.BooleanField(required=False, label='RB')
mr = forms.BooleanField(required=False, label='MR')
CHOICES = [('rb' ,'RB'), ('mr', 'MR')]
analyse_type = forms.ChoiceField(choices=CHOICES, widget=forms.RadioSelect)
template html
...
{{ form.analyse_type }}
Here I would like to test which button is selected and display the template depending of the selection
something like : {% if form.analyse_type.? == true %}
...
I test a lot of syntaxe with form.analyse_type.? like form.analyse_type.field.widget.choices to have each choices in a loop ect. , but I do not found the right one returning the selected radiobutton...
Maybe this way is not the right one to do what I want.
If you have any idea, solution thank you ;)
Edit for user2497126
Thanks for all tips :) !
I have an error Uncaught Error: GET_ELEMENTS: -> form[data-sb-form-api-token] seems to be in link with the object analyse_type
As requested, following a print screen with the html element.I tired different synthaxe like
let radioValue =$("input[name='analyse_type']:checked").value();
I also put my HTML code in case
{% extends "index.html" %}
{% load static %}
{% block content %}
<div style="padding-left: 30%;" class="col-lg-6 col-xl-6"
<h2 class="h4 fw-bolder">
Analyse Type
</h2>
<br>
{{ form.analyse_type }}
<br> </div>
<div id="template-one" style="display:none;">
<div style="padding-right: 30%;" class="col-lg-6 col-xl-6">
<h2 class="h4 fw-bolder">
TEST
</h2>
</div>
</div>
{% endblock %}
{% block javascript %}
<script type="text/javascript">
$(document).ready(function () {
$(".custom-control-input").change(function () {
let radioValue = $("input[name='analyse_type']:checked").value();
let templateOne = document.getElementById('template-one')
if (radioValue == "rb") {
$("#template-one").show();
} else {
$("#template-one").hide();
}
});
});
</script>
{% endblock javascript %}
EDIT
if I do a
console.log($("input[name='analyse_type']:checked").val())
in the debugger of chrome I have a return of rb.
But the error is still there with no result.
I also change the html, include the template-one in the same div of the form like your example
The problem seems here
$(".custom-control-input").change(function () {
I replace .custom by select or select#id_analyse_type, based on some forum answers, but I have no result
Thanks for your time and your help :)
EDIT
Here the solution :
{% block javascript %}
<script type="text/javascript">
$(document).ready(function () {
let radioValue = $("input[name='analyse_type']:checked").val();
if (radioValue == "rb") {
$("#template-one").show();
} else {
$("#template-one").hide();
}
$('#id_analyse_type').change(function () {
let radioValue = $("input[name='analyse_type']:checked").val();
if (radioValue == "rb") {
$("#template-one").show();
} else {
$("#template-one").hide();
}
});
});
</script>
{% endblock javascript %}
Thank you for your help !
Here is an edited answer which I have tried to adapt to your question
For the change function (i.e when selecting the radio) inspect and replace the class value with the one in your radio input. Also ensure you supply the correct name when instantiating the variable radioValue, I have used 'analyze_type' for the sake of the example but inspect and confirm the correct name value of the radio input.
You can achieve it using JS like this in your template
{% extends "base.html" %}
{% block title %}Form title{% endblock title %}
{% block content %}
<!-- page content -->
<div class="x_content">
{{ form.analyse_type}}
<div id="template-one" style="display:none;">
Template one
</div>
<div id="template-two" style="display:none;">
Template two
</div>
</div>
<!-- /page content -->
{% endblock %}
{% block javascript %}
<script>
$(document).ready(function(){
$(".custom-control-input").change(function(){
let radioValue = $("input[name='analyse_type']:checked").val();
let templateOne = document.getElementById('template-one')
if(radioValue == "RB"){
$("#template-one").show();
$("#template-two").hide();
}
else {
$("#template-two").show();
$("#template-one").hide();
}
});
});
</script>
{% endblock javascript %}

Populating dropdown in Django using Ajax

I have several dropdowns in my form, which I am looking to populate using Ajax from backend. Given below are the relevant code segments:
HTML:
<div class="row">
<div class="col-xs-6">
<div class="col-xs-6">
<label name="start_date" class="control-label" style="width:35%">Start date</label>
<input type="date" style="color:black;width:100px" ></input>
</div>
</div>
<div class="col-xs-6">
<label name="end_date" class="control-label" style="width:35%">End Date(Default: Current Date)</label>
<input style="color:black;width:100px" type="date"></input>
</div>
</div>
<div class="row">
<div class="col-xs-6">
<label name="fruit" class="control-label" style="width:35%; padding-left:15px">Select a Fruit</label>
<select style="width:150px;height:30px">
{% for option in options.fruit %}
<option value="{{ option }}">{{ option }}</option>
{% endfor %}
</select>
</div>
<div class="col-xs-6">
<label name="vendor" class="control-label" style="width:35%">Select a vendor</label>
<select style="width:150px;height:30px">
{% for option in options.vendor %}
{{ option }}
<option value="{{ option }}">{{ option }}</option>
{% endfor %}
</select>
</div>
</div>
{% block script %}
<script>
document.onload = function(){
$.ajax({
url : window.location.href,
type:'GET',
cache:false,
data:{type:'formdata'},
success:function(res){
if(typeof res.options == 'undefined'){
self.options = res.options;
}
if(typeof res.options.start_date == 'undefined'){
self.form.start_date = res.options.start_date;
}
if(typeof res.options.end_date == 'undefined'){
self.form.end_date = res.options.end_date;
}
if(typeof res.options.fruit == 'undefined'){
window.fruit = res.options.fruit;
}
if(typeof res.options.vendor == 'undefined'){
window.vendor = res.options.vendor;
}
},
error : function(err){
self.message = "Error getting data for the form";
}
});
}
</script>
{% endblock %}
Both the drop downs are independent of each other. The data is being given at the front end through this view:
class Search(View):
def get(self, request):
if request.GET.get('type') == 'formdata':
options = {'fruit': [], 'vendor': []}
try:
cursor = connections['RDB'].cursor()
options['end_date'] = today.strftime('%Y-%m-%d')
last_week_date = today - timedelta(days=7)
options['start_date'] = last_week_date.strftime('%Y-%m-%d')
options['fruit'] = [a[0] for a in cursor.fetchall()]
options['vendor'] = [a[0] for a in cursor.fetchall()]
return JsonResponse({'options': options})
The back end is working perfectly fine, the options dictionary is getting populated as I expected it to. However the drop down options are not showing up on the front end. Where am I going wrong? Any help is greatly appreciated.
Maybe try using select2 it's a pretty good utility for populating select boxes through Ajax, even has a search functionality in built. Here's a simple example.
html -
<html>
<head>
<title>Using Select2</title>
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
<!-- Select2 CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/css/select2.min.css" rel="stylesheet" />
</head>
<body>
<div class="jumbotron">
<div class="container bg-danger">
<div class="col-md-6">
<label>Single Select2</label>
<select class="js-data-example-ajax"></select>
</div>
</div>
</div>
<!-- jQuery -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<!-- Select2 -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.6-rc.0/js/select2.min.js"></script>
<script>
$('.js-data-example-ajax').select2({
ajax: {
url: 'https://api.github.com/search/repositories',
dataType: 'json'
// Additional AJAX parameters go here; see the end of this chapter for the full code of this example
}
});
</script>
</body>
</html>
Don't forget to import the relative JS and CSS CDN's.

Jinja, loading javascript script

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

Display Form Field based on other Fields within the Django Form

I am trying to create a way to only display certain fields within a django form based on the bound data of another field within that same form. I'm familiar with the idea of form.field.bound_type but I'm not sure how to continually check for state change on a field in a form and update the other field accordingly. Something like if you were filling out an application and it asked if you've committed a crime, if you click yes then a details text area pops up.
I'm using:
Django 1.8.4
Bootstrap3 6.6.2
As it pertains to this question. Here is what I've currently got with the field values edited for work protection. It does SORT of work. Meaning the form is fine, the if statement works initially but it doesn't reevaluate the if once the specified field has changed.
<form action= "/send_email/" method="post" class='col-sm-5'>
{% csrf_token %}
{% bootstrap_field form.field_one%}
{% bootstrap_field form.field_two%}
{% bootstrap_field form.field_three%}
{% if form.field_three.bound_data == "A Value" %}
{% bootstrap_field form.field_four%}
{% endif %}
{% buttons %}
<button type="submit" class="btn btn-primary">
{% bootstrap_icon "glyphicon glyphicon-ok-circle" %} Submit
</button>
{% endbuttons %}
</form>
Solution:
With Birdie's help I was able to figure out the solution. For anyone who has hit this same Django related problem here is how you add or remove fields based on another field in the same form.
<script>
// function that hides/shows field_four based upon field_three value
function check_field_value(new_val) {
if(new_val != 'A value') {
// #id_field_four should be actually the id of the HTML element
// that surrounds everything you want to hide. Since you did
// not post your HTML I can't finish this part for you.
$('#field_four').removeClass('hidden');
} else {
$('#field_four').addClass('hidden');
}
}
// this is executed once when the page loads
$(document).ready(function() {
// set things up so my function will be called when field_three changes
$('#field_three').change( function() {
check_field_value(this.value);
});
});
</script>
<form action= "/send_email/" method="post" class='col-sm-5'>
{% csrf_token %}
{% bootstrap_field form.field_one%}
{% bootstrap_field form.field_two%}
<div id="field_three">{% bootstrap_field form.field_three%}</div>
<div id="field_four">{% bootstrap_field form.additional_notes %}</div>
{% buttons %}
<button type="submit" class="btn btn-primary">
{% bootstrap_icon "glyphicon glyphicon-ok-circle" %} Submit
</button>
{% endbuttons %}
</form>
You cannot do this within the template because the template is executed on the server side, but the user interaction occurs on the client side.. in the browser. This must be done in javascript and run in the browser.
Here is an example of jQuery code which does this. I did not test it so it may need tweaking, but this should get you in the right direction.
You will need to look at your HTML to determine the id of the element you actually want to hide() and show(). Normally you would have some kind of HTML element (eg. a DIV) surrounding both the field or fields you want to hide as well as the label(s).. and you would hide everything at once by hiding the element which contains all the fields, rather than each individual field itself.
If you add the HTML surrounding field_four to your question, I will update the answer to work with what you've got...
<script>
// Ideally this script (javascript code) would be in the HEAD of your page
// but if you put it at the bottom of the body (bottom of your template) that should be ok too.
// Also you need jQuery loaded but since you are using bootstrap that should
// be taken care of. If not, you will have to deal with that.
// function that hides/shows field_four based upon field_three value
function check_field_value() {
if($(this).val() == 'A Value') {
// #id_field_four should be actually the id of the HTML element
// that surrounds everything you want to hide. Since you did
// not post your HTML I can't finish this part for you.
$('#id_field_four').hide();
} else {
$('#id_field_four').show();
}
}
// this is executed once when the page loads
$(document).ready(function() {
// set things up so my function will be called when field_three changes
$('#id_field_three').change(check_field_value);
// set the state based on the initial values
check_field_value.call($('#id_field_three').get(0));
});
</script>
Thanks all for the contribution, but I could not get the code above work. This is my solution:
<script>
function hideField() {
check = document.getElementsByName("put your field name here")[0].value;
response = document.getElementById("put your id here");
if (check === "Open") {
response.style.display = "none";
}else{
response.style.display = "block";
}
}
</script>
The key is to figure out Id for the field you want to hide, and name for the field you check. I did NOT use DIV container to assign the id and the name, but inspected rendered HTML page with developer tools in the browser. Let me know if you have questions or want more detailed explanation.
I found this question very interesting. I have updated it with bootstrap 4.0v, with the following script, I hope it can help someone:
<script>
// function that hides/shows field_four based upon field_three value
function check_field_value(new_val) {
if(new_val != 'A value') {
// #id_field_four should be actually the id of the HTML element
// that surrounds everything you want to hide. Since you did
// not post your HTML I can't finish this part for you.
$('#field_four').removeClass('d-none');
} else {
$('#field_four').addClass('d-none');
}
}
// this is executed once when the page loads
$(document).ready(function() {
// set things up so my function will be called when field_three changes
$('#field_three').change( function() {
check_field_value(this.value);
});
});
</script>
<form action= "/send_email/" method="post" class='col-sm-5'>
{% csrf_token %}
{% bootstrap_field form.field_one%}
{% bootstrap_field form.field_two%}
<div id="field_three">{% bootstrap_field form.field_three%}</div>
<div id="field_four">{% bootstrap_field form.additional_notes %}</div>
{% buttons %}
<button type="submit" class="btn btn-primary">
{% bootstrap_icon "glyphicon glyphicon-ok-circle" %} Submit
</button>
{% endbuttons %}
</form>

Customize count list

I have this code I'm using to generate a list of records categorized into year, make, series, body style, and color for vehicles. I'd like to customize this further this way:
for the year, I want to have only up to 2004 being individual...the rest will fall under other i.e. 2009, 2008, 2007, 2006, 2005, 2004, Other.
for the make, I want to display the six makes with the highest popularity...there's a field in the model I'm using to assign the popularity of a make with a value of primary (highest), secondary or tertiary. The rest will fall under Other.
For the body style and color, I want to have the items having less than 3 records falling under Other.
My code is as below:
year_count = vehicle_query.order_by(
'-common_vehicle__year__year').values('common_vehicle__year__year').
annotate(count=Count('id'))
make_count = vehicle_query.order_by(
'common_vehicle__series__model__manufacturer__manufacturer').
values('common_vehicle__series__model__manufacturer__manufacturer').
annotate(count=Count('id'))
style_count = vehicle_query.order_by(
'common_vehicle__body_style__style').values
('common_vehicle__body_style__style').annotate(count=Count('id'))
colour_count = vehicle_query.order_by(
'exterior_colour__exterior_colour').values(
'exterior_colour__exterior_colour').annotate(count=Count('id'))
The bulk of what you're asking would probably better be handled outside of Django and instead by client-side javascript. To be clear, you could have portions handled by Django, but it would be cleaner not doing so. There are benefits to doing it this way:
Your Django template code stays cleaner
It will degrade nicely
You can later update the interface (change the javascript) and not have to worry about breaking the Django template
To handle this you could simply make a script that when given a <ul> tag (and maybe some arguments) will render that list in the format you're asking about.
Here's a simple example using jQuery. For this example, I'm going to wrap the functionality in a using a jQuery plugin pattern.
Say your django template outputs the following...
<ul>
<li>Chevy</li>
<li>Mazda</li>
<li>Honda</li>
<li>Ford</li>
<li>BMW</li>
</ul>
jquery.showmorelist.js
(function($) {
$.fn.ShowMoreList = function(visibleItemCount) {
// Wrap parent element
var parent = $(this).wrap('<div class="show-more-list"></div>').parent();
var ul = $(this);
// Enumerate children and hide extras
var counter = 0;
$(this).children().filter('li').each(function(){
counter += 1;
if (counter > visibleItemCount) {
$(this).hide();
$(this).addClass('hidden');
}
});
// Add link and bind click
var link = $('> Show More').click(function(){
$(ul).children().filter('.hidden').show();
});
$(parent).append(link);
}
})(jQuery);
page.html
<script type="text/javascript" src="jquery.showmorelist.js"></script>
<script type="text/javascript">
// On page load...
$(function() {
$('ul').ShowMoreList(4); // Shows only the first 4 items
});
</script>
This is a rather simple example, and it won't switch the "Show More" to "Hide More" but you should be able to figure that out from the context.
I managed to get a solution, so I thought it'd be good to update the answer here:
In the head section I have this:
<script type="text/javascript" src="{{ MEDIA_URL }}share/jquery/jquery.min.js"></SCRIPT>
<script type="text/javascript">
(function($) {
$(document).ready(function() {
//hide the additional content under "Display More"
$("div.additional_content").hide();
$("a.more").click(function () {
//show or hide the additional content
$(this).siblings("div.additional_content").toggle();
//change the attributes and text value of the link toggle
if($(this).text() == "Display Less"){
$(this).removeClass("less");
$(this).addClass("more");
$(this).html("Display More");
}else{
$(this).removeClass("more");
$(this).addClass("less");
$(this).html("Display Less");
}
return false;
});
});
})(jQuery);
Then wherever I want to reduce the number of available options I have this:
<div class="module_wrap">
<div class="module"> {% if year_count %} <strong>{% trans "Year" %}</strong> <br />
{% for item in year_count|slice:":6" %}
<ul>
<li> {{ item.common_vehicle__year__year }} ({{ item.count }}) {% if request.session.chosen_year %} <img src="{{ MEDIA_URL }}img/undo.gif" border="0" alt="Remove Year Filter" title="Remove Year Filter" /> {% endif %} </li>
</ul>
{% endfor %}
<div class="additional_content"> {% for item in year_count|slice:"6:" %}
<ul>
<li> {{ item.common_vehicle__year__year }} ({{ item.count }})</li>
</ul>
{% endfor %} </div>
{% if year_count|slice:"6:" %}Display More<br />
{% endif %} <br />
</div>
</div>
{% endif %}