I'm having a few problems trying to create a cascading drop down list in web2py. I've followed this recipe, however, It is quite difficult for me (a beginner) to suss out the logic behind it.
http://www.web2pyslices.com/slice/show/1526/cascading-drop-down-lists-with-ajax-2
i've managed to adapt it slightly, but i'm having trouble trying to add more tables to the cascade/sequence
So at the moment i have the code below, what i'm trying to do is return a list of values from the "tax_class" table based selecting results from the "tax_phylum" table
model
db.define_table('tax_kingdom',
Field('name'))
db.define_table('tax_phylum',
Field('name', 'string'),
Field('kingdom_id'))
db.tax_phylum.kingdom_id.requires = IS_IN_DB(db, db.tax_kingdom.id, '%(name)s')
db.define_table('tax_class',
Field('name', 'string'),
Field('phylum_id'))
db.tax_class.phylum_id.requires = IS_IN_DB(db, db.tax_phylum.id, '%(name)s')
Controller
def index():
kingdoms = db().select(db.tax_kingdom.ALL)
if request.vars.kingdom_name:
phylum_select = db(db.tax_phylum.id == request.vars.kingdom_name).select(db.tax_phylum.ALL)
else:
phylum_select = db(db.tax_phylum.id == 1).select(db.tax_phylum.ALL)
return dict(kingdoms=kingdoms, phylum_select=phylum_select)
def phylum():
phylums = db(db.tax_phylum.kingdom_id == request.vars.kingdom_name).select(db.tax_phylum.ALL)
result = ""
for p in phylums:
result += "<option value='" + str(p.id) + "'>" + p.name + "</option>"
return XML(result)
view
{{extend 'layout.html'}}
<form enctype="multipart/form-data" action="{{URL()}}" method="post">
<select name='kingdom_name'
onchange="jQuery('#kingdom_name').empty();
ajax('phylum', ['kingdom_name'], 'phylum_name');">
{{for kingdom in kingdoms:}}
<option value="{{=kingdom.id}}"
{{=" selected='selected'" if str(kingdom.id)==request.vars.kingdom_name else ""}}>
{{=kingdom.name}}
</option>
{{pass}}
</select>
<select id='phylum_name' name='phylum_name' >
<!-- loop through the index function i -->
{{for phylum in phylum_select:}}
<option value="{{=phylum.id}}"
{{=XML(" selected='selected'") if str(phylum.id)==request.vars.phylum_name else ""}}>
{{=phylum.name}}</option>
{{pass}}
</select>
</form>
Related
I'm getting trouble trying to update my Object in the back-end via a front-end template.
This is my template, it uses ThymeLeaf
<form id="formUpdate" method="put">
<div class="row">
<div class="col s12">
<h2> Modificar Gustos</h2>
</div>
</div>
<div class="divider"></div>
<div class="row">
<label for="selectGusto">Nombre del gusto a cambiar</label>
<select name="gustos" id="selectGusto">
<option value="-1" selected="selected" disabled="disabled">Lista de Gustos</option>
<option th:each="gusto : ${gustos}" th:text="${gusto.nombre}" th:value="${gusto.id}"> </option>
</select>
</div>
<label for="newName">Nuevo Nombre</label>
<input type="text" name="newName" id="newName" />
<div class="row">
<label for="selectCat">Elegir nueva Categoria</label>
<select name="newCat" id="selectCat">
<option value="-1" selected="selected" disabled="disabled">Nueva Categoria</option>
<option value="Dulces de Leche">Dulce de Leche</option>
<option value="Cremas">Cremas</option>
<option value="Chocolates">Chocolates</option>
<option value="Frutales">Frutales</option>
</select>
</div>
<button type="submit" id="btn-submit" class="button">Modificar</button>
</form>
This is my JS linked to the template:
var newCatId;
var idGusto;
var newName;
$('#selectCat').on('change', () => {
var value = $('#selectCat').val();
if(value === "Dulces de Leche") {
newCatId = 1;
}
else if(value === "Cremas") {
newCatId = 2;
}
else if(value === "Chocolates") {
newCatId = 3;
}
if(value === "Frutales") {
newCatId = 4;
}
console.log('newCatId: ' + newCatId);
console.log('idGusto ' + idGusto);
console.log('newName: ' + newName);
});
$('#selectGusto').on('change', function() {
idGusto = $(this).val();
});
newName = $('#newName').val();
$('#btn-submit').on('submit', (e) => {
e.preventDefault();
var url = idGusto + " '/edit' + '/' "+ newName + '/' + newCatId;
$('#formUpdate').attr('action', url);
});
And this is the Spring controller that should handle the request:
#RequestMapping(value = "/gustos/{id}/edit/{newName}/{newIdCat}")
public String updateGustoById(#PathVariable("id") int id, #PathVariable("newIdCat") int newIdCat, #PathVariable("newName") String newName){
Gusto gusto = gustoService.findGustoById(id);
gusto.setNombre(newName);
gusto.setIdCategoria(newIdCat);
gustoService.update(gusto);
return "redirect:/gustos/edit";
}
Ok !! This code doesn't breaks anywhere but when I click on the submit button the variables in the JS travel in the URL as a Query String, that's not what I want to.
Example of my URL after clicking the form's submit button:
http://localhost:8080/gustos/edit?gustos=106&newName=Dulce+de+Leche+Granizado&newCat=Dulces+de+Leche
This is my first time making a Spring App!
My question is, how can I send the information to the controller in the right way? How do people normally update an Object if is not like this? :(
EDIT: The expected values are OK, that means the JS is working OK. The problem is sending the values to the back-end !! The form is sending them as a Query String and that's not what I need, neither the assigned values on the Query String are fine
In Your Scenario, Your trying to form path param URL
1.Instead of path params you can directly specify the action attribute in form element
<form id="formUpdate" method="GET" action="http://localhost:8080/gustos/edit">
method attribute can be GET or POST according to your need.
And newCat Select box like
<select name="newCat" id="selectCat">
<option value="-1" selected="selected" disabled="disabled">Nueva Categoria</option>
<option value="1">Dulce de Leche</option>
<option value="2">Cremas</option>
<option value="3">Chocolates</option>
<option value="4">Frutales</option>
</select>
In Backend you can use #RequestParam to get paramter values
#RequestMapping(value = "/gustos/edit")
public String updateGustoById(#RequestParam(value="gustos") int id, #RequestParam(value="newCat")
int newIdCat, #RequestParam(value="newName") String newName)
{
Gusto gusto = gustoService.findGustoById(id);
gusto.setNombre(newName);
gusto.setIdCategoria(newIdCat);
gustoService.update(gusto);
return "redirect:/gustos/edit";
}
2.Another approach, Construct a JSON string with form field values (like you did for path params), While Submitting the form send this JSON string to back end through ajax call.
On your service layer keep this JSON String as Java beans (Spring Boot bind JSON values with the bean fields through #RequestBody annotation, if bean structure matched with the JSON).
I would recommend using th:object in your form. This creates an object of a given type instantly when you submit your form. So, let's say your object is of type Gusto. If you want to create a new entity from scratch, you could add this method in your controller that will return a new entity of type Gusto.
New Model Attribute
// In order to use th:object in a form, we must be able to map a new entity to that form.
// In this case we return a Gusto entity.
#ModelAttribute(value = "newGusto")
public Gusto newGusto() {return new Gusto();}
Form
So now, you can use this entity in a form using th:object="${newGusto}". This will create a new entity for you, which you might mapped fields to it.
In order to do so you would need to add following one elements to your form.
<form action="/gustos/edit/" id="formUpdate" method="put" th:object="${newGusto}">
<div class="row">
<div class="col s12">
<h2> Modificar Gustos</h2>
</div>
</div>
<div class="divider"></div>
<div class="row">
<label for="selectGusto">Nombre del gusto a cambiar</label>
<select th:field="*{id}" name="gustos" id="selectGusto">
<option value="-1" selected="selected" disabled="disabled">Lista de Gustos</option>
<option th:each="gusto : ${gustos}" th:text="${gusto.nombre}" th:value="${gusto.id}"> </option>
</select>
</div>
<label for="newName">Nuevo Nombre</label>
<input th:field=*{nombre} type="text" name="newName" id="newName" />
<div class="row">
<label for="selectCat">Elegir nueva Categoria</label>
<select th:field="*{categoria} name="newCat" id="selectCat">
<option value="-1" selected="selected" disabled="disabled">Nueva Categoria</option>
<option value="Dulces de Leche">Dulce de Leche</option>
<option value="Cremas">Cremas</option>
<option value="Chocolates">Chocolates</option>
<option value="Frutales">Frutales</option>
</select>
</div>
<button type="submit" id="btn-submit" class="button">Modificar</button>
</form>
The only difference you will find with your current code, is the added th:field elements in your selects and inputs and the th:object. Each one of these inputs and selects, will automatically mapped each field to the new entity you just created in your form.
Controller
Now for your controller you would need to change it for the following.
#RequestMapping(value = "/gustos/edit/")
public String updateGusto(#ModelAttribute("newGusto") Gusto gustoToUpdate){
Gusto gusto = gustoService.findGustoById(gustoToUpdate.getId());
gusto.setNombre(gustoToUpdate.getNombre());
gusto.setIdCategoria(gustoToUpdate.getCategoria());
gustoService.update(gusto);
return "redirect:/gustos/edit";
}
Of course, in your case, it is important that you change your jquery. We don't want to change the URL now. We just want to submit the form. So the following code, would have to be removed.
$('#btn-submit').on('submit', (e) => {
e.preventDefault();
var url = idGusto + " '/edit' + '/' "+ newName + '/' + newCatId;
$('#formUpdate').attr('action', url);
});
public static WebElement residentialStatus(String name) {
element = LoginPage.driver.findElement(By.xpath("PATH"));
Select oSelect = new Select(element);
oSelect.selectByVisibleText(name);
System.out.println("Residential Status: " + name);
return element;
}
the HTML is:
<select name="residentialStatus">
<option value="">--Please Select--</option>
<option value="B">Boarding</option>
<option value="O">Home Owner</option>
<option value="P">Living with Relative</option>
<option value="R">Renting</option>
In the above code, I am trying to select a Dropdown,
When I am selecting 'Home Owner' it fails (possible because there is a Space), when I choose 'Boarding' or 'Renting' then it works fine.
I am unable to understand where I am going wrong.
(Feeding Data from Excel, so I can't change it to 'selectByArray as all other dropdowns are working fine from the same excel)
I want design a web form,its have to control one Text Box and one Drop Down list when type a number between 5 and 10 in Text Box, Drop Down list is include 1,2,3,4,5 and when type a number between 11 and 20 in Text Box, Drop Down list is include 6,7,8,9,10.
How to do it without page refreshing?
please explain with code.
I think the following code may help you.
<select id="txt" onchange="changeNumber()">
<option>select value</option>
<option>10</option>
<option>11</option>
<option>12</option>
<option>13</option>
<option>14</option>
<option>15</option>
<option>16</option>
<option>17</option>
<option>18</option>
<option>19</option>
<option>20</option>
</select>
<select id="mySelect">
<option>21</option>
<option>22</option>
<option>23</option>
<option>24</option>
</select>
<script>
function changeNumber(){
var t_value=document.getElementById('txt').value;
if(t_value==10 ||t_value==11 || t_value==12 || t_value==13 || t_value==14 || t_value==15 ){
var x = document.getElementById("mySelect").selectedIndex;
var y = document.getElementById("mySelect");
var j=1
for(var i=0;i<=y.options.length;i++){
y[i].text=j;
j++;
}
}
}
</script>
In this way you can solve your 2nd problem.
You can also follow the below code.
<input type="text" id="txt" onkeyup="checkValue();" />
<select id="mySelect">
<option>21</option>
<option>22</option>
<option>23</option>
<option>24</option>
</select>
<script>
function checkValue(){
var t_value=document.getElementById('txt').value;
if(t_value==10 ||t_value==11 || t_value==12 || t_value==13 || t_value==14 || t_value==15){
var x = document.getElementById("mySelect").selectedIndex;
var y = document.getElementById("mySelect");
var j=1
for(var i=0;i<=y.options.length;i++){
y[i].text=j;
j++;
}
}
}
</script>
I think this type of solution you need.
<form:select id="name1"
<form:options items="${questionsMap}"/>
</form:select>
<form:select id="name2"
<form:options items="${questionsMap}"/>
</form:select>
<form:select id="name3"
<form:options items="${questionsMap}"/>
</form:select>
The questions map come from enum.Can anyone please help how can I remove the question from the questionsMap after it is selected on the first select and display the unselected ones the second time.
You can not do it on a JSP, as the code there will run on the server side - if you don't want do extra queries to the server... So the best way is to do it with JavaScript. Jquery selectors make this task easy.
Suggestion: http://api.jquery.com/remove/
Also, events that might interest you:
http://api.jquery.com/change/
There you can even find a as example...
Just to put my example here:
$( "select" ).change(function () {
$( "select option:selected" ).each(function() {
$( this ).remove();
});
})
Instead of removing options from the drop-down you could simply validate the same options selected and show the error message on submit.
var validateSubmit = function() {
var errors = [];//trace all errors here
//fetch selected values from the drop-down starting name attribute with `name`
var txt = $('select[name^=name]').map(function() {
return this.value; //get current drop-down selected value
}).get(); //get all value in array
$.each(txt, function(i, v) {//loop in the selected values
if (i !== $.inArray(v, txt)) {//inArray, gives -1 if not found else array index
errors.push('Cannot select [' + v + '] more than once');
}
});
var submit = 0 === errors.length//true if no errors, else false
if (!submit) {
alert(errors.join('\n'));//concat all errors with \n
}
return submit;//submit if true, else don't submit
};
$(function() {
$('#form1').on('submit', validateSubmit);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<form id='form1'>
<select name='name1'>
<option>JS</option>
<option>SQL</option>
<option>XML</option>
</select>
<select name='name2'>
<option>JS</option>
<option>SQL</option>
<option>XML</option>
</select>
<select name='name3'>
<option>JS</option>
<option>SQL</option>
<option>XML</option>
</select>
<button>Submit</button>
</form>
OR
You could simply validate the same options selected and show the error message on change.
var names;
var validateChange = function() {
var errors = []; //trace all errors here
//fetch selected values from the drop-down starting name attribute with `name`
var txt = names.map(function() {
return this.value; //get current drop-down selected value
}).get(); //get all value in array
$.each(txt, function(i, v) { //loop in the selected values
if ('' !== v && i !== $.inArray(v, txt)) { //inArray, gives -1 if not found else array index
errors.push('Cannot select [' + v + '] more than once');
}
});
if (errors.length) {
alert(errors.join('\n')); //concat all errors with \n
}
};
$(function() {
names = $('select[name^=name]');
names.on('change', validateChange);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<select name='name1'>
<option value=''>-- Select --</option>
<option>JS</option>
<option>SQL</option>
<option>XML</option>
</select>
<select name='name2'>
<option value=''>-- Select --</option>
<option>JS</option>
<option>SQL</option>
<option>XML</option>
</select>
<select name='name3'>
<option value=''>-- Select --</option>
<option>JS</option>
<option>SQL</option>
<option>XML</option>
</select>
This is a jquery code I made which does exactly this. Also leaves empty values in (if you have "Please select" in the top) and reinserts unselected values. It does it for all select elements on the page, if you need to restrict replace the selector $("select") with a more specific one:
$( document ).ready(function() {
manageSelectValues();
$("select").change(manageSelectValues);
});
function manageSelectValues()
{
$("select").each(function() {
var id = $(this).attr('id');
var value = $(this).find(":selected").val();
if (value) {
$("select[id!='" + id + "']").find("option").filter(function() { return this.value == value;}).remove();
}
$(this).find("option").filter(function() { return this.value != value;}).each(function() {
var unselValue = $(this).val();
$("select").filter(function() { return $(this).find("option").filter(function() { return this.value == unselValue;}).length == 0; }).append(
$('<option></option>').val(unselValue).html(unselValue));
})
});
}
I am working on a jsp project where I have a dynamic selection list. The values in this list change according to the value selected in the 1st selection list.
Here's the code:
<script language="JavaScript" type="text/javascript">
function optionsChange(){
var service = document.getElementById("service").value;
if(service == 'GSM'){
document.getElementById("cdmaService").value= '';
document.getElementById("cdmaService").style.display = 'none';
document.getElementById("gsmService").style.display = 'block';
$('gsmService').attr('name', 'services');
}else if(service == 'CDMA'){
document.getElementById("gsmService").value= '';
document.getElementById("gsmService").style.display = 'none';
document.getElementById("cdmaService").style.display = 'block';
$('cdmaService').attr('name', 'services');
}
}
</script>
<select id="service" onChange="javascript:optionsChange();">
<option value="GSM">GSM</option>
<option value="CDMA">CDMA</option>
</select>
<td id="gsmService" ><select name="services" >
<option value="COMBO OFFER">COMBO OFFER</option>
<option value="CRICKET">CRICKET</option>
<option value="ASTRO">ASTRO</option>
</select>
</td>
<td id="cdmaService" style="display:none"><select name="services" >
<option value="COMBO OFFER CDMA">COMBO OFFER CDMA</option>
<option value="WIN THE DREAM">WIN THE DREAM</option>
<option value="VOICE CHAT">VOICE CHAT</option>
</select>
</td>
now when the user selects a service, lets say "GSM", and then selects a service from the second list, lets say "ASTRO". He clicks on a button which redirects him to the next page where he sees "ASTRO" printed. This works fine.
But if the user selects "CDMA" from the 1st list and then selects, let's say "VOICE CHAT" from the second list. It still prints "ASTRO" on the next page. IT should print "VOICE CHAT".
this is the method to submit form:
<script language=javascript>
function submitForm(actionStr)
{
if(actionStr=="User Details")
{
document.login.action="showUsrDetail.jsp";
document.login.submit();
}
}
this is the code for the button:
<input type="button" value="User Details" onclick="submitForm(this.value);"/>
then it redirects to the page ""showUsrDetail.jsp". And when it does the name of the service is printed on the console. For which the code is:
<%
String service = request.getParameter("services");
System.out.println("Value Added Service selected is ="+service);
%>
if i change the first selection to CDMA and then select any service from the second selection list, it still prints the Service which is under GSM.
Can somebody please help me out?
You can write a javascript function to get the selected value instead of getting the same from servlet. Put the Javascript function in script tab with language as JavaScript.
function JSGetSelectedItem() {
var dropdownIndex = document.getElementById('service').selectedIndex;
var dropdownValue = document.getElementById('service')[dropdownIndex].text;
}
<select id="service" onChange="JSGetSelectedItem()">
<option value="GSM">GSM</option>
<option value="CDMA">CDMA</option>
</select>