Mashup: Select Box / Disabled Input / Getting Info From Database - javascript

I am creating a form, where people can either choose a new team and then input its location or if they select a team from the list, I would like the input to be disabled - and the selected team's location to be given in the input box. This is my code so far. It doesn't work. :(
<select id="chooseTeam" name="chooseTeam" data-placeholder="Select Team">
<option></option>
{% for team in teams %}
<option>{{team.name}}</option>
{% endfor %}
<option>New Team</option>
</select>
<input type="text" id="input_location" name="input_location"/>
In a separate JS File:
$(document).ready(function() {
$('#chooseTeam').on('blur', function() {
if (form.chooseTeam.value != "New Team" && form.chooseTeam.value != "Select Team") {
$("#input_location").html("{{team.location}}");
document.getElementById("input_location").disabled = true;
}
});
});
MINI-UPDATE
Apparently, AJAX is needed for this. I am brand new to Javascript (3 days old) so I don't know how AJAX works yet but I am at this moment googling it to try and figure it out.
Oh, and Merry Christmas, everybody!
"#code-on-christmas"

It seems that you are using Django and jQuery. Is that true? I cannot give you a fully detailed answer at the moment, but the code in the following line cannot work because you are mixing client-side and server-side code.
$("#input_location").html("{{team.location}}");
The expression {{team.location}} cannot be evaluated by Django because it only exists on the client-side in your browser. If you want Django to evaluate what has been chosen on the client-side, you should use AJAX calls between server and client by using $.ajax().
Also, why don't you use jQuery selectors for all of your code? Do something like this:
$(document).ready(function() {
$('#chooseTeam').on('blur', function() {
var currentTeam = $(this).val();
if (!$.inArray(currentTeam, ['New Team', 'Select Team'])) {
$("#input_location").attr('disabled', 'disabled');
}
});
});

Related

Django Form - Conditional field display using JQuery

This implementation is using Django 4.0 and Bootstrap5 with CrispyForms.
Objective: The user selecting a value in one field determines whether another field is shown or hidden. By default, the conditional field has a value of "No". The impacted field will be shown when the user changes the conditional field to the value of "Yes". Specifically, if the user selects "Yes" for the field Recurring event the field Recurrence pattern will be shown.
Please note that the implementation of Class Based Views in the template is working great. Here's a screenshot of the form (with the conditional field requirement not working):
Existing code (relevant snippets only)
Here's what I have in models.py:
YES_NO_CHOICES = [
('No', 'No'),
('Yes', 'Yes'),
]
RECURRENCE_PATTERN_CHOICES = [
('---', '---'),
('Daily', 'Daily'),
('Weekly', 'Weekly'),
('Monthly', 'Monthly'),
('Yearly', 'Yearly'),
]
class Event(models.Model):
event_name = models.CharField(
max_length=70,
help_text='''Enter a name for the event. This is a required field and is limited to 70 characters.'''
)
recurring_event = models.CharField(
max_length=5,
choices=YES_NO_CHOICES,
default='No',
help_text='''Is this a one off event or will it recur? Selecting Yes will open up additional fields.'''
)
recurrence_pattern = models.CharField(
max_length=10,
choices=RECURRENCE_PATTERN_CHOICES,
default='---',
help_text='''Select the recurrence pattern for this event.'''
)
Here is what I have in forms.py:
class EventStaffSummaryUpdateView(UpdateView):
"""Event Staff Update view - allows staff to change event details"""
model = Event
template_name = 'events/event_staff_summary_form.html'
fields = [
'event_name',
'recurring_event',
'recurrence_pattern',
]
context_object_name = 'event'
In the event_staff_summary.html template (using inheritance) I have:
<div class="content-section">
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<div id="event_name">
{{ form.event_name|as_crispy_field }}
</div>
<div id="recurring_event">
{{ form.recurring_event|as_crispy_field }}
</div>
<div id="recurrence_pattern">
{{ form.recurrence_pattern|as_crispy_field }}
</div>
</fieldset>
<div class="form-group pt-4 pb-2">
{% if page_type == 'Update' %}
<button class="btn btn-BlueGray" type="submit">Update Event</button>
{% else %}
<button class="btn btn-BlueGray" type="submit">Create Event</button>
{% endif %}
</div>
</form>
</div>
In the base.html template I am using the Google JQuery link (found on my journey as a simple way of implementing JQuery):
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
As you can see with the screenshot, the form itself is displaying perfectly. So models, form and even the html is working to this point. The update class based view is working with the DB. All that remains is to show or hide Recurrence pattern based on the value in the field Recurrence event. Which brings me to...
What have I tried so far?
Of the 10+ JS snippets I've come across and tried, here is the leading candidate that seems to be closest. I really want this to work as it makes sense to me.
<script>
$("#recurring_event").change(function() {
if ($(this).val() === "Yes") {
$('#recurrence_pattern').show();
} else {
$('#recurrence_pattern').hide();
}
});
</script>
Request
Has anyone got suggestions on how I can get this working? I've got requirements for a number of conditionally displayed fields. I'd prefer to not work from checkboxes as typically this client prefers to explicitly have the user click Yes or No as this is clearer to them (they feel there is no chance of ambiguity with a closed question and a yes/no choice).
This requirement of conditional fields in forms is implemented in many instances, so I know I'm not seeking the impossible. I am hoping that there's a simple refinement (or clean up) of the javascript snippet I've posted. I also welcome other JS suggested snippets too.
Thanks in advance for your help.
ANSWER (Feb 27)
Following the issuance of a bounty #Swati came through with a solution posted in a fiddle here: https://jsfiddle.net/L8ke03hc/ As soon as they post the answer I'll award the Bounty. I'd like to thank Tony for coming really close and getting me on the right track. The final piece of the puzzle was the .trigger event to call the change function.
<script>
$(document).ready(function() {
$("#id_recurring_event").change(function() {
if ($(this).val() === "No") {
$('#div_id_recurrence_pattern').hide();
} else {
$('#div_id_recurrence_pattern').show();
}
});
$("#id_recurring_event").trigger("change")
})
</script>
Thanks to all that came through on this one. This was a profound learning experience for me. I really need to spend some time learning JS. That said, I've got the solution. May anyone trying to build conditional logic in Django/CrispyForms benefit from this. I am so grateful for the Open Source community! <3
Update library to
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
Wrap function in a DOM ready event.
Update selector to a <select> (from div). Do this by inspecting DOM.
End result:
(function($){
$(document).ready(function(){
$("#id_recurring_event").change(function() {
if ($(this).val() === "Yes") {
$('#id_recurrence_pattern').show();
} else {
$('#id_recurrence_pattern').hide();
}
});
})
})(jQuery);
You can use trigger() method to achieve this . So, whenever your page gets load called this to execute the change event which is attached on select-box .
Working code :
$(document).ready(function() {
$("#id_recurring_event").change(function() {
if ($(this).val() === "No") {
$('#recurrence_pattern').hide();
} else {
$('#recurrence_pattern').show();
}
});
$("#id_recurring_event").trigger("change")
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<div class="content-section">
<form method="POST">
<fieldset class="form-group">
<div id="event_name">
ABC ..
</div>
<div id="recurring_event">
<select id="id_recurring_event">
<option value="Yes">Yes</option>
<option value="No" selected="true">No</option>
</select>
</div>
<div id="recurrence_pattern">
somethings ..................
</div>
</fieldset>
</form>
</div>

How to deal with dependable dropdowns in Django

I am trying to create a dependable dropdown on Django but since my JavaScript/ajax knowledge is not great, I have hit rock bottom. Note: I have read previous questions on this matter but none of them fully solved my problem.
Problem Description:
Due to my database size, I am retrieving partial data from the server whenever a view is requested. This makes my job of using forms harder since I am using the username of the user to filter my server. Here is a simplified version of my code.
urls.py
urlpatterns = [
url(r'^SpecificVessel', views.SpecificVessel, name="goSpecificVessel"),
]
views.py
#login_required
def SpecificVessel(request):
#Get the username to filter the tables from SQL Server:
username = None
if request.user.is_authenticated:
username = request.user.username
#Get the shipnames.
cursor.execute("select distinct SHIPNAME from Table where [GROUP]=" + "'" + username + "'")
row = cursor.fetchall()
df_listofships = pd.DataFrame(data=row, columns=['SHIPNAME'])
shipnames = list(df_listofships['SHIPNAME'].tolist()) # LIST FOR SHIP SELECTION
#Get All the data from database.
cursor.execute("select * from Table2 where [GROUP]=" + "'" + username + "'")
row = cursor.fetchall()
df = pd.DataFrame(data=row)
colnames = list(dftrans.columns.values.tolist()) #LIST FOR YEAR DROPDOWN SELECTION
#getting the dropdown selections:
Dropdown_shipname = request.POST.get('Dropdown_shipname')
Dropdown = request.POST.getlist('Dropdown')
return render(request, 'SpecificVessel.html',
{'colnames': colnames, 'Dropdown': Dropdown, 'shipnames': shipnames, 'Dropdown_shipname': Dropdown_shipname,})
SpecificVessel.html
<form method="post">
{% csrf_token %}
<div class="form-group col-md-4">
<label for="Dropdown_shipname"><b>Select Vessel</b></label>
<select name="Dropdown_shipname" id="Dropdown_shipname" data-style="btn-default" class="selectpicker form-control" >
{% for i in shipnames %}
<option value="{{ i }}" {% if Dropdown_shipname == i %} selected {% endif %}>{{ i }} </option>
{% endfor %}
</select>
</div>
<div class="form-group col-md-4">
<label for="Dropdown"><b> Select Month </b></label>
<select name="Dropdown" id="Dropdown" data-style="btn-default" class="selectpicker form-control" multiple>
{% for i in colnames %}
<option value="{{ i }}" {% if Dropdown == i %} selected {% endif %} >{{ i }} </option>
{% endfor %}
</select>
</div>
<div class="form-group col-md-1 margin_top_25">
<input type="submit" value="Submit" />
</div>
</form>
What is the problem?
The solution I have in the code above provides me with independent dropdowns. That is, whenever there is a mismatch, it throws me an error. I have been trying to approach this in different way, however, after long research online, I found out that javascript or ajax may be the way to go about this. My question is this: Is there any way in which I could get what the user has selected in Dropdown_shipname before he submits the results? If yes, how would you solve this problem?
I hope I was clear enough. Please let me know if I should explain the problem any better.
There's a lot I feel I need to address before answering your main question.
The if request.user.is_authenticated bit is unnecessary; you already decorate the view with #login_required, so there's no way the user isn't authenticated.
Where does cursor come from? It doesn't look like you're using Django's database stuff (the ORM, or even raw cursors), but something else? Why is that?
Having a global cursor may lead to trouble down the line in production, when it's being shared between requests in a multithreaded situation. (Using Django's database functionality the database connections are correctly reset between requests, and each thread gets its own connection.)
Your SQL queries are vulnerable to SQL injection attacks, since you're just concatenating strings together. You need to use placeholders (parametrized queries) instead. How that's done depends on the database and database driver you're using.
You definitely don't need Pandas and a Pandas dataframe to extract the data from your database result! (My pet peeve: useless use of Pandas.)
The first retrieval would be shipnames = [row[0] for row in cursor].
The second retrieval would be colnames = [d[0] for d in cursor.description] (or similar; depends on your database). (However, you really don't want to fetch a number of rows just to get the column names; one row, e.g. LIMIT 1 in standard SQL, would do.)
You should be using Django forms to manage, well, forms. That way you don't need to manage rendering the <select>s and <option>s and selecteds manually.
This view would likely become a FormView subclass.
You say "This makes my job of using forms harder since I am using the username of the user to filter my server.", but that's a non-issue. You can well pass in your Django request, or just the User, or an username, to a custom form class, and have it modify or even add fields dynamically to the form based on it.
That said, the most minimal solution here is a tiny bit of JavaScript, to refresh the page with an added query string argument for the first selection. That is, when the user changes the shipname field, you'd refresh the page with e.g. ?shipname=selection-here, and deal with figuring out the correct choices for the other field in your view code.
The most minimal way I can think of is
<script>
document.getElementById("Dropdown_shipname").addEventListener("change", (event) => {
location.href = `?shipname=${event.target.value}`;
}, false);
</script>
Beyond that, you could use an AJAX request to selectively refresh only part of the page, and beyond that, maybe refactor the form into, say, a React.js or Vue.js component that deals with the form.
But either way, no, you're not going to be able to dynamically change the other field without JavaScript.

Dynamically update Javascript variables using Jinja?

I have a web form created that requires template creation by the user. Calling all previous entries that are templates isn't an issue, but passing the information to the form when called seems to be tricky. Basically I want the user to be able to select a template from the dropdown (See the screenshots and stuff below), then based on their selection, update the variables in the script to autofill form data. Right now, it only selects the most recent entry. Is this possible just using python/flask/javascript or am I missing something? Any help would be appreciated! Thanks!
Template Dropdown
<label for="template_select">Select Template</label>
<select class="form-control" name="template_select" id='template_select' onchange='changeTemplate()'>
<option value=''></option>
{% for template_info in template_search %}
<option value='{{template_info.client_name}}'>{{template_info.client_name}}</option>
{% endfor %}
</select>
Javascript to change values
{% for template_info in template_search %}
<script>
function changeTemplate(){
var template = document.getElementById('template_select').value;
document.getElementById('client_name').value='{{template_info.client_name}}';
document.getElementById('client_name').innerHTML='{{template_info.client_name}}';
}
</script>
{% endfor %}
Python Passing in the Query
template_search = newmatter_model.NewClientMatter.query.filter_by(
creator=verifier, is_template='on').all()
Your mistake is to create Javascript code in a loop. You don't need to do this.
What you want to do is think of the data sent to the browser as independent. Make it work first without Flask and Jinja2. Create a static page that works and does what you want.
The following code would work with static data:
function changeTemplate(){
var template = document.getElementById('template_select').value;
document.getElementById('client_name').innerHTML = template;
}
<label for="template_select">Select Template</label>
<select class="form-control" name="template_select" id="template_select" onchange="changeTemplate()">
<option value=""></option>
<option value="Client 1">Client 1</option>
<option value="Client 2">Client 2</option>
<option value="Client 3">Client 3</option>
</select>
<div id="client_name"><i>No client set</i></div>
That's HTML for a select box, a separate <div> element, and Javascript code to copy the selected option value into the <div>. Note that the Javascript code doesn't know anything about what data is involved; no client names are stored in the code. All that the small function does is to copy the value from the currently selected option, to somewhere else.
Once that works on its own you can start thinking about how you are going to insert the values from your application. In the above code, all that needs replacing is the dropdown options, because the Javascript code can then access everything it needs from the <select> element value.
So the Javascript code doesn't need to be generated at all, you only generate the <option> elements, as you already did in your question.
You rarely need to generate dynamic Javascript code, and it would be much better for your app if you don't. Static Javascript code can be served by a CDN and cached in the browser, removing the need for your app to keep serving that again and again for all clients. Try to minimise that whenever you can.
Instead, generate just the data that the code needs to operate on.
You can put that information in HTML tags. In the above example, your data is put in the repeated <option> tags. Or
you could add data attributes to your HTML, which are accessible both to Javascript code and to CSS. Or
use AJAX to load data asynchronously; e.g. when you pick an option in the <select> box, use Javascript and AJAX to call a separate endpoint on your Flask server that serves more data as JSON or ready-made HTML, then have the Javascript code update your webpage based on that. Or
generate JSON data and put it directly into your HTML page. Just a <script>some_variable_name = {{datastructure|tojson|safe}};<script> section is enough; then access that some_variable_name from your static Javascript code to do interesting things on the page. JSON is a (almost entirely a) subset of Javascript, and the way the tojson filter works is guaranteed to produce a Javascript-compatible data structure for you. The browser will load it just like any other embedded Javascript code.

Can the value obtained by dijit.byId('').value be compared to a String?

I am relatively new to Spring MVC and Dojo/Dijit widgets and I am stuck with a problem. I need to unblock a particular div based on the option selected from the dropdown i.e. when the user selects the reason as "Unexperienced" I am supposed to unblock a div with id = "unexpUser" style="display:none;" to collect some additional information.
JSP -
<select data-dojo-type="dijit.form.Select" name="userReason" id = "reason">
<option value="opt0">Experienced</option>
<option value="opt1">Not experienced</option>
</select>
JC -
<script>
if(dijit.byId('reason').value == "opt1"){
unexpUser.style.display = 'block';
}
</script>
When the page loads, the option displayed on the dropdown is "Experienced". When I change the option to "Not experienced" , I need to unblock the div but this particular code doesn't seem to be the right code for comparing. Please help.
.value is not the right way to get value from a dijit widget instead use:
dijit.byId('reason').get("value")
Use onchange listener :
dijit.byId('reason').on("change",function(evt){
alert(evt); //(evt == value of option )
// your code here
});
okay I got my mistake. This is the solution. #Harpreet Singh your solution works perfectly with this code.
JSP-
<form:select data-dojo-type="dijit.form.Select" path "" name="userReason" id = "reason" onchange="myFunction1();">
<option value="opt0">Experienced</option>
<option value="opt1">Not experienced</option>
</form:select>
and in my JS I created a function for the String comparison.
JS -
<script>
function myFunction1(){
if(dijit.byId('reason').get("value") == "opt1"){
unexpUser.style.display = 'block';
}
</script>
this works. Thank you so much for your help!

Adding values to a select box using ajax and organising javascript files

I want to create a page where everything is loaded via ajax calls, so the URL always stays the same. At first the user will be presented with one box with some choices. According to the choice he makes another one will appear and again according to the choice he makes on the second a third will appear. I have successfully created this logic using ajax bit like the following. I am sorry if the code is a bit meshed up, but I am typing the question from a different machine than my code is located, so please be gentle. If you have any problem I will try to provide as much info as I can. So the html
<!DOCTYPE html>
<html>
<head etc....>
<body>
<div class="main-nav">
</div><!--some navigation things here not important-->
<div class=controls>
<div class="select-control1">
<select>
<option selected="selected" value="">Choose one of the following</option>
<!-- adding the django code for this select-->
{% for option in options %}
<option value="{{option.id}}">{{option.name}}</option>
{%endfor%}
</select>
</div>
<div class="select-control2" style="display:none;">
<select>
<option selected="selected" value="">Choose one of the following</option>
</select>
</div>
</div>
</body>
<html>
Also the option1 and 2 in each control1 are prepopulated by a django template for tag (it is a django project).
the ajax calls are triggered on change of each control and the view that is executed from behind sends an array of json_objects
$(".select-control1 select").change(function (){
option = $(this).prop("value");
//Skipping the case where option value is "" for now
$.ajax({
url:'/url/to/view/',
dataType:'json',
type:'GET',
success:onSuccess1
});
});
function onSuccess1(data, status, jqXHR){
$.each(data, function(index, value){
html = "<option value="+value['id']+">"+value['option']+"</option>";
$(".select-control2 select").append(html);
});
$(".select-control2").show();
}
As i said not intrested in error checking or what happens if user checks a different option in select-control1. I do remove them and place the newly gotten ones from the ajax call, just didn't right that right now. My problem are 2 + 1. First of all when the second control is populated with options after the ajax call the "Choose one of the following" option dissappears. Is that the natural behaviour of append?Is there another way?
Second even though i have the selected attribute in the first control in the "Choose one...." option when the page is loaded i don't it won't appear as selected but it will give one of the options loaded from django e.g. option1
Third and final: I am fairly new to ajax and javascript in general, and this kind of programming. I am familiar with procedural languages and can organize them as I want. But Javascript is giving me a hard time. Right now I have a veeery large js file, that will include all ajax and jquery calls of all elements on the page. Is there a way to "modulize" it in a way, to seperate it in different files somehow?Any good links pages books that could give me a guidness?
Thanks in advance!!
This is because of "<option value="+value['id']+>". You missed "
It should be
"<option value="+value['id']+">"+
Or simply try
$(".select-control2").append(new Option(value['option'], value['id']));
If your browser is IE8, the above code won't work. In such cases you have to use something like this,
var opt = new Option(value['option'], value['id']));
$(opt).html(value['option']);
$(".select-control2").append(opt);

Categories

Resources