To generate an HTML select we can use the Grails tag <g:select .../>. We use the optionValue attribute to specify a specific property we want to be used as the value. But we can also define a closure for the optionValue attribute to further customize the value that is shown to the user.
Suppose we have a simple domain class Book with a couple of properties. We want to combine multiple properties as the text for the HTML select options. In the following GSP we define first a <g:select .../> tag where we simply use the title property. In the next <g:select .../> tag we use a closure to combine multiple properties.
We can also pass the closure as model property to the GSP from a controller. In a controller we define the transformation in a closure and pass it along to the GSP page. On the GSP we can use this closure as a value for the optionValue attribute of the <g:select .../> tag. The following GSP shows all three scenarios.
<%@ page import="com.mrhaki.grails.sample.Book" contentType="text/html;charset=UTF-8" %>
<html>
<head>
<title>Simple GSP page</title>
<meta name="layout" content="main"/>
<style>
p { margin-top: 20px; margin-bottom: 5px;}
</style>
</head>
<body>
<h1>Select</h1>
<p>Use title property of book for option values</p>
<g:select from="${Book.list()}"
optionKey="id"
optionValue="title"
name="bookSimple"/>
<p>Use closure for optionValue</p>
<g:select from="${Book.list()}"
optionKey="id"
optionValue="${{ book -> "${book.title} - ${book.isbn}" }}"
name="bookCustom"/>
<g:set var="bookOptionValueFormatter"
value="${{ book -> "${book.title} (${book.isbn}, ${book.numberOfPages})" }}"/>
<p>Use bookOptionValueFormatter that is defined as variable on this page</p>
<g:select from="${Book.list()}"
optionKey="id"
optionValue="${bookOptionValueFormatter}"
name="bookVar"/>
<p>Use bookFormatter that is passed as a model property from SampleController.</p>
<g:select from="${Book.list()}"
optionKey="id"
optionValue="${bookFormatter}"
name="bookModel"/>
</body>
</html>
Here is a sample controller which passes the transformation to the GSP:
package com.mrhaki.grails.sample
class SampleController {
def index() {
final formatter = { book -> "$book.title (pages: $book.numberOfPages)" }
[bookFormatter: formatter]
}
}
When we run the application and open the page in a web browser we get the following HTML source:
... <h1>Select</h1> <p>Use title property of book for option values</p> <select name="bookSimple" id="bookSimple" > <option value="1" >It</option> <option value="2" >The Stand</option> </select> <p>Use closure for optionValue</p> <select name="bookVar" id="bookCustom" > <option value="1" >It - 0451169514</option> <option value="2" >The Stand - 0307743683</option> </select> <p>Use bookOptionValueFormatter that is defined as variable on this page</p> <select name="bookVar" id="bookVar" > <option value="1" >It (0451169514, 1104)</option> <option value="2" >The Stand (0307743683, 1472)</option> </select> <p>Use bookFormatter that is passed as a model property from SampleController.</p> <select name="bookModel" id="bookModel" > <option value="1" >It (pages: 1104)</option> <option value="2" >The Stand (pages: 1472)</option> </select> ...
The optionKey attribute also allows closures as arguments.
Code written with Grails 2.3.2.