Set Option Key and Value on Grails select list? - grails

I am currently working on a Grails application and I am looking place a select list on the page and have its Key set to one value and the Value set to another. The code of all related elements is below:
Domain Object:
class Cars {
String carType
String car
}
Controller:
def create() {
List cars = Cars.list()
[dealerInstance: new Dealer(params), cars: cars]
render(text:"This site in curently under Maintainence!")
}
View:
<g:select name="cars.id" from="${cars}" optionKey="${carType}" optionValue="${car}"/>
Now when I run this code the list does get populated however data looks like below:
<select id="cars.id" name="cars.id">
<option value="com.app.Cars : 1">com.app.Cars : 1</option>
<option value="com.app.Cars : 2">com.app.Cars : 2</option>
<option value="com.app.Cars : 3">com.app.Cars : 3</option>
</select>
and then when I try this:
View:
<g:select name="cars.id" from="${cars.car}" optionKey="${carType}" optionValue="${car}"/>
I get the following:
<select id="cars.id" name="cars.id">
<option value="Audi">Audi</option>
<option value="BMW">BMW</option>
<option value="Scoda">Scoda</option>
</select>
This is not what I want at all I want to be able to set a different Key Value pair on this select list so that I can use that data within my application, I would want the following to be generated:
<select id="cars.id" name="cars.id">
<option value="Saloon">Audi</option>
<option value="Hatch Back">BMW</option>
<option value="Estate">Scoda</option>
</select>
Can someone please tell me how I achieve this within Grails???

Try this:
<g:select id="cars.id" name="cars.id" from="${cars}" optionKey="carType" optionValue="car"/>
What basically happens:
When you use the from attribute, the tag iterates over the list you passed as an argument. optionKey and optionValue should be strings representing the attributes you want to access in the current object (being accessed by the iterator).

Related

how to set selected value in drop down menu depending on conditions

I have code with drop down menu. The object for this menu has few fields. Two of them are playerPosition and isFirstSquadPlayer.
If isFirstSquadPlayer is TRUE I need to display in menu player.playerPosition.
Trying on few ways but failed.
My controller:
public String players(#PathVariable long clubId, Model model) {
Club club = this.clubRepository.findByClubId(clubId);
model.addAttribute("players", this.playerRepository.findAllByPlayerClub(club));
return "players";
}
My HTML:
<select name="playerposition"
id="createnewplayerposition" th:value="${player.playerPosition}" required>
<option value="0">Select position for player</option>
<!--HERE NEED PROPER REQUEST -->
<option th:selected="${player.playerPosition}" th:text="${player.playerPosition}"></option>
<option value="GK">Goalkeeper</option>
<option value="RWB">Right Wingback</option>
<option value="RCB">Right Centreback</option>
(...)
</select>
as per kindly advice:
ok, tried and found such request with thymeleaf conditional:
<option th:if="${player.playerPosition!=null}" th:selected="${player.playerPosition}" th:text="${player.playerPosition}"></option>
it's not excactly how I expected but gives some solution –

how to thymeleaf select row value parameter jquery function?

How can I send the selected line value?
<select th:onchange="changes(this.getAttribute('data-test'))">
<option th:each="list : ${allList}"
th:value="${list?.number}"
th:text="${list?.name}"
th:data-test="${list?.test}">
</option>
</select>
onchange(list.test) value parameter ....
This should work (in your case, this refers to the select object, and not an option).
<select th:onchange="changes(this.options[this.selectedIndex].dataset.test)">
<option th:each="list : ${allList}"
th:value="${list?.number}"
th:text="${list?.name}"
th:data-test="${list?.test}">
</option>
</select>

thymeleaf multiple selected on edit

I am totally changing this question, as part of it was answered here with great help of Avnish!
Tom sent me to the right direction so thank you Tom!
My problem is that I do not know how to tell Thymeleaf to preselect object elements when editing it.
Let me show you:
This solution works:
<select class="form-control" id="parts" name="parts" multiple="multiple">
<option th:each="part : ${partsAtribute}"
th:selected="${servisAttribute.parts.contains(part)}"
th:value="${part.id}"
th:text="${part.name}">Part name</option>
</select>
I have tried this:
<select class="form-control" th:field="*{parts}" multiple="multiple">
<option th:each="part : ${partsAtribute}"
th:field="*{parts}"
th:value="${part.id}"
th:text="${part.name}">Part name</option>
</select>
did not work. I also tried this:
<select class="form-control" th:field="*{{parts}}" multiple="multiple">
<option th:each="part : ${partsAtribute}"
th:field="*{parts}"
th:value="${part.id}"
th:text="${part.name}">Part name</option>
</select>
did not work either. I have tried removing th:field="*{parts}" from the option tag, same result..
If I change th:value to ${part} it works, but then it does not send back string of ids like [2,4,5,6,...], but Part instances like [Part#43b45j, Part#we43y7,...]...
UPDATE: I just noticed that this works if only one part is selected:
<select class="form-control" th:field="*{parts}" multiple="multiple">
<option th:each="part : ${partsAtribute}"
th:field="*{parts}"
th:value="${part.id}"
th:text="${part.name}">Part name</option>
</select>
If multiple parts are selected, it does not work.
After discussion on the Thymeleaf forum, I implemented a full working example at
https://github.com/jmiguelsamper/thymeleafexamples-selectmultiple
I think that the only problem with your final code is that you have to use double bracket syntax to invoke the conversionService:
th:value="${{part}}"
It is also important to implement proper equals() and hashcode() methods in your Part class to assure proper comparison.
I hope my example helps other users with similar problems in the future.
You don't need th:selected when using th:field normally. Thymeleaf will automatically check the values of each <option> in the <select>, even if it is multiple
The problem lies in the value. You are iterating over parts, but the value of each option is part.id. Thus you are comparing instances of part to the id of part (as far as I can see).
However, Thymeleaf also takes into account instances of PropertyEditor (it reuses org.springframework.web.servlet.tags.form.SelectedValueComparator).
This will be used when comparing the objects to the values of the options. It will convert the objects to their text value (their id) and compare this to the value.
<select class="form-control" th:field="*{parts}" multiple="multiple" >
<option th:each="part : ${partsAttribute}"
<!--
Enable the SpringOptionFieldAttrProcessor .
th:field value of option must be equal to that of the select tag
-->
th:field="*{parts}"
th:value="${part.id}"
th:text="${part.name} + ${part.serial}">Part name and serial No.
</option>
</select>
Property Editor
Define a PropertyEditor for the parts. The PropertyEditor will be called when comparing the values, and when binding the parts back to the form.
#Controller
public class PartsController {
#Autowired
private VehicleService vehicleService;
#InitBinder(value="parts")
protected void initBinder(final WebDataBinder binder) {
binder.registerCustomEditor(Part.class, new PartPropertyEditor ());
}
private static class PartPropertyEditor extends PropertyEditorSupport {
#Override
public void setAsText(String partId) {
final Part part = ...; // Get part based on the id
setValue(part);
}
/**
* This is called when checking if an option is selected
*/
#Override
public String getAsText() {
return ((Part)getValue()).getId(); // don't forget null checking
}
}
}
Also take a look at ConvertingPropertyEditorAdapter. Converter instances that are registered in the conversionService are more preferred in Spring nowadays.
This works for me:
A vet has many specialties.
Controller:
#RequestMapping(value = "/vets/{vetId}/edit", method = RequestMethod.GET)
public ModelAndView editVet(#PathVariable("vetId") int ownerId/*, Model model*/) {
ModelAndView mav = new ModelAndView("vets/vetEdit");
mav.addObject("vet", this.vets.findById(ownerId));
mav.addObject("allSpecialties", this.specialities.findAll());
return mav;
}
View (using th:selected):
<select id="specialities" class="form-control" multiple>
<option th:each="s : ${allSpecialties}"
th:value="${s.id}"
th:text="${s.name}"
th:selected="${vet.specialties.contains(s)}">
</option>
</select>
View (using th:field):
<form th:object="${vet}" class="form-horizontal" id="add-vet-form" method="post">
<div class="form-group has-feedback">
<select th:field="*{specialties}" class="form-control" multiple>
<option th:each="s : ${allSpecialties}"
th:value="${s.id}"
th:text="${s.name}"
>
</option>
</select>
</div>
And I have to define Specialty findOne(#Param("id") Integer id) throws DataAccessException; in the SpecialtyRepository, otherwise the following exception is thrown : "java.lang.IllegalStateException: Repository doesn't have a find-one-method declared!"
package org.springframework.samples.petclinic.vet;
import java.util.Collection;
import org.springframework.dao.DataAccessException;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
public interface SpecialtyRepository extends Repository<Specialty, Integer> {
#Transactional(readOnly = true)
Collection<Specialty> findAll() throws DataAccessException;
Specialty findOne(#Param("id") Integer id) throws DataAccessException;
}
Here's how I did it:
<select th:field="*{influenceIds}" ID="txtCategoryName" class="m-wrap large" multiple="multiple">
<option th:each="influence : ${influences}" th:value="${influence.get('id')}" th:text="${influence.get('influence')}" ></option>
</select>
My DTO contains:
private List<String> influenceIds;
<select id="produtos" name="selectedItens" style="width: 100%;" multiple="multiple" required="">
<option th:value="${p.id}" th:text="${p}" th:each="p : ${slideShowForm.itens}" th:selected="${#lists.contains(slideShowForm.selectedItens,p)}"></option>
</select>
<select th:field="*{groupId}" >
<option th:each="group :${grouptype}"
th:value="${{group.groupId}}"
th:text="${group.Desc}">
</option>
</select>
Simple select example

Enum rendering as string representation in MVC 3 View

I have the following enumerator in my code:
Public Enum UserSearchFields
LastName
FirstName
Email
UniqueID
End Enum
I try to populate a drop down list in the view with the values from this enumerator:
<select id="search_type">
<option value="#UserSearchFields.LastName" selected="selected">Last Name</option>
<option value="#UserSearchFields.FirstName">First Name</option>
<option value="#UserSearchFields.Email">E-mail</option>
<option value="#UserSearchFields.UniqueID">Unique ID</option>
</select>
But for some reason when page is rendered the value field contains the string representations of the enumerator not the underlying integer values. For example the option value field will be "LastName" instead of "0"... Why is this the case and am I making some sort of mistake?
P.S. I'm aware that I can populate a drop down list from an Enumerator such as How do you create a dropdownlist from an enum in ASP.NET MVC? but i just would like to know why is this issue happening?
I think you need to set the enums to a number like so:
Public Enum UserSearchFields
LastName = 0
FirstName = 1
Email = 2
UniqueID = 3
End Enum
Even if this is an unecessary step, you need to cast it to an int when you write it out like so:
<select id="search_type" style="width: 100%;">
<option value="#((int)SOLEPortal.UserSearchFields.LastName)" selected="selected">Last Name</option>
<option value="#(((int)SOLEPortal.UserSearchFields.FirstName)">First Name</option>
<option value="#((int)SOLEPortal.UserSearchFields.Email)">E-mail</option>
<option value="#((int)SOLEPortal.UserSearchFields.UniqueID)">Unique ID</option>
</select>
A better way to do this would be to create an extension method that automatically writes out a drop down list from an enum, but this is a good starting place.

Submitting form elements with the same name

I have a form which allows the user to create extra "rows" using JQuery (using .clone) so that they can decide how many of the same information they need to submit. My issue is that I cannot work out how to access these form items within my controller.
the form that is being submitted may look like this
<input type="text" name="Amount" id="Amount">
<select name="Item">
<option value="1">Item 1"</option>
<option value="2">Item 2"</option>
<option value="3">Item 3"</option>
</select>
<input type="text" name="Amount" id="Amount">
<select name="Item">
<option value="1">Item 1"</option>
<option value="2">Item 2"</option>
<option value="3">Item 3"</option>
</select>
<input type="text" name="Amount" id="Amount">
<select name="Item">
<option value="1">Item 1"</option>
<option value="2">Item 2"</option>
<option value="3">Item 3"</option>
</select>
Basically, the block between input and the select could be repeated an infinite number of times. When I submit to the controller I am then using FormCollection form to access the form elements. from there I am unsure how I can access the items that have been submitted. I thought of using a for loop and then accessing them via something like form["Amount"][i] but obviously that is not going to work.
Am I going about this the right way and if so, does anyone have any suggestions about how this might work?
Thanks in advance.
Old question, but still...
You can get the posted values as an array by calling Request.Form.GetValues, or Request.QueryString.GetValues. For example:
string[] amounts = Request.Form.GetValues("Amount");
And the amounts array will contain the correct values, so you can post values containing comas, dots, whatever, and don't worry about splitting/parsing it.
Of course if you are running MVC, use the modelbinder to do it. But you can use this if you are using webforms, a generic handler, etc...
Check out Model Binding To A List. Your Action method should be:
public ActionResult MyAction(string[] Amount, int[] Item){
// ...
}
However this will make you need to "link" the items. Alternatively create a "Item" class:
public class Item {
public string Amount { get; set; }
public int Item { get; set; }
}
And
public ActionResult MyAction(IList<Item> items){
// ...
}
And your markup should be:
<input type="hidden" name="items.Index" value="0" />
<input type="text" name="items[0].Amount" id="items[0].Amount">
<select name="items[0].Item">
<option value="1">Item 1"</option>
<option value="2">Item 2"</option>
<option value="3">Item 3"</option>
</select>
<input type="hidden" name="items.Index" value="1" />
<input type="text" name="items[1].Amount" id="items[1].Amount">
<select name="items[1].Item">
<option value="1">Item 1"</option>
<option value="2">Item 2"</option>
<option value="3">Item 3"</option>
</select>
Etc...
I believe if you have multiple fields named Amount the values will be comma delimited.
To access each one just try:
string[] amounts = Request.Form["Amount"].Split(new char[] { ',' });
Keep in mind though, the inputs are not cleaned on submission so if someone enters a comma into the text box it's going to cause issues.
Hence I'd recommend numbering them.
I ended up realising that (blush) the mechanism which JQuery uses to find the string within the cloned row (to replace) is basically regex. Thus I just needed to escape the square brackets and period. Once I did this I was able use JQuery to create form as Phil Haack's blog suggested.
Onto my next issue...!
I would number them Amount1, Amount2, Amount3 etc.
You can change the id and name attribute of the input to something like this "Amount[1]","Amount[2]","Amount[3]" (yes, the id and name attribute can contain the special chars "[" or "]"). Then in the controller, write a http request parameter parser to get back the Amounts as collections.

Resources