I have a simple domain something like this:
class Family {
String name_en
String name_fr
}
In a controller I retrieve all the records in that domain with an executiveQuery like this:
def family =Family.executeQuery("select new Map(name_en as name_en, name_fr as name_fr) from Family")
I'm simplify the actual code for the sake of clarity. Then I have a GSP page that show this data, but I want to show based on the language.
So generally I get the language with this code:
<g:set var="lang" value="${org.springframework.web.servlet.support.RequestContextUtils.getLocale(request).getLanguage()}"/>
but how can I select the name based on the language, here I got the en
<g:each in="${family}" status="index" var="record">
${record?.name_en}
</g:each>
I thought I could do something like this, but of course it doesn't work:
${record?.name_`lang`}
I think it would be easiest to use a dynamically generated property name in this case:
${record?."name_${lang}"}
One of the great things about GString & Groovy.
You will need a bunch of if-then-else.
<g:each in="${family}" status="index" var="record">
<g:if test="${lang == 'en'}">
${record?.name_en}
</g:if>
<g:elseif test="${lang == 'fr'}">
${record?.name_fr}
</g:elseif>
</g:each>
Related
I've done some research on how to display a dropdown with an optional value. Currently, I have a list of domain objects (people) in a dropdown. They display with "First name last name".
I want to change the way the names are displayed in a selection. Looking at the g:select API, I see I can use optionValue and optionKey. I've tried, but got nowhere. So here is my current code:
<g:select id="allPeople" name="allPeople" from="${dropdown}" />
I want the output to be "Last, First". I've tried this:
<g:select id="allPeople" optionValue="${it?.last},${it?.first}" from="${dropdown}" name="allPeople" value="" >
A nice way to do it is to add a transient getter on your domain, then use that for the optionValue.
class Person {
String first
String last
static transients = ['lastFirst']
String getLastFirst() {
"$last, $first"
}
}
then
<g:select name="allPeople" optionValue="${it.lastFirst}" from="${dropdown}"/>
Try like this:
optionValue="${{it?.last+', '+it.first}}"
This mean that you pass a closure that builds what you need.
On my view, instead of using a normal <g:textField> field in the form, I would like to make use of Grails' <g:countrySelect> widget.
My problem
<g:countrySelect name="country" value="${myObjInstance?.country}"/>
...produces...
<select name="country" id="country">
<option value="afg">Afghanistan</option>
<option value="alb">Albania</option>
...
</select>
This would mean that, when the form is submitted, it will assign the value as country code (e.g. "afg") instead of the country name ("Afghanistan"). I prefer using the full country name as value. If possible, how do I achieve this?
I don't believe the taglib as is gives you that ability. You would either need to extend it or use your own Country collection + <g:select />
Another option would be to use this enum of the ISO_3166 country codes to get the full length description. Eg:
CountryCode.getByCode(params.country).getName()
To answer my own question...
The values can stay as is (country codes) and then just use country codes. On your views, you can make use of the grails country() method to display the country name, e.g.
Let's say the country code is "afg" (the value saved in your table). On your view (GSP) you can use
<div>${country(code: fieldValue(bean: myObjInstance, field: "country"))}</div>
This will print out
<div>Afghanistan</div>
Instead of
<div>${fieldValue(bean: myObjInstance, field: "country")}</div>
...that was used before:
<div>afg</div>
I have a list of domain objects in GSP view and would like to check if any of them are of particular type:
Class Equipment {}
Class Loader extends Equipment {}
... in view:
<g:each in="${Equipment.list()}" var="e">
... check if e is a Loader....
</g:each>
I'm trying to do the check if a GSP fragment to build a nav menu and wonder if this even the right spot to do the check in.
If you're making the logic in a GSP complex like that you should consider creating a taglib instead. It'll be easy to test too - GSPs need to be tested with functional tests and a running web server, but you can test taglibs with integration tests.
You can try:
<g:each in="${Equipment.list()}" var="e">
<g:if test="${e instanceof your.package.Loader}">Do anything</g:if>
</g:each>
Is there a way to break out of a <g:each>? I have a page wherein I'm iterating through a list and I have to make sure that a checkbox is checked if that was the value stored in DB.
To make it a little clearer, please consider something like:
<g:each in=${list1}>
<g:each in=${list2}>
<g:if test="${list1.id == list2.id}">
<input type="checkbox" ... checked="checked" />
</if>
</g:each>
...
</g:each>
where list1 is, say Domain1.list() (i.e. ALL possible values) and list2 is Domain2.find(...) (i.e. SELECTED values)
In the g:each, I need to display ALL of list1 (hence, the "..." after the inner each) with a checkbox but I need to make sure that those in list2 (user-selected items that were saved to DB) should be checked accordingly (if statement).
Now, if the checked status was changed on the first iteration, i need to get out of the inner each... any way to do this?
Thanks!
Nope, not with the each clause.
I'd just write my own taglib that takes list1 and list2 and does the iteration for you, yielding back to the
<g:eachCheckedItem list1="${list1}" list2="${list2}">
<input type="checkbox" ... checked="checked"/>
</g:eachCheckedItem>
And in your taglib class:
def eachCheckedItem = { attrs, body ->
def list1 = attrs.list1
def list2 = attrs.list2
list1.findAll { list2.contains(it) }.each {
out << body(listItem: it) // access to listItem variable inside gsp
}
}
Something like that (tuned to your specific problem) is easy to write, and also cleans up your gsp file quite a bit. I use these kinds of custom iterators all the time in my taglibs.
If I understood you correctly, you need something like this:
<g:each var="elem1" in="${list1}">
<g:if test="${list2.any{it.id==elem1.id}}">
<input type="checkbox" checked="checked" />
</g:if>
...
</g:each>
There is no g:any tag, but as Ted pointed out, it would be easy to write one (left as an exercise to the reader). Then you could simplify the the inner tag to something like this:
<g:any test="${it.id==elem1.id}" in="${list2}">...</g:any>
You should do this in the model, so you then only have a simple loop in the view. Then it's just a matter of making the controller call Domain.findMyList() or whatever.
For the googlers looking for an answer to the original poster's question, there isn't a break command in gsp. There are some better responses here, the best one of which in my opinion is try and make use of .findAll { .. } to find only the set you would expect to work on prior to a 'break'.
http://markmail.org/message/tt2einl3ntwgzdep#query:grails%20gsp%20break%20out%20of%20loop+page:1+mid:nzhgwdsgkrwkurt4+state:results
can anybody tell me why this works
<g:each var="n" in="${com.pp.News.list()}">
<h2>${n.t}</h2>
<p>${n.tx}</p>
</g:each>
but this doesn't ?
<g:set var="news" value="${com.pp.News.findAllByShow(true,[sort:'prio', order:'desc',max:5])}" />
<g:each var="n" in="news">
<h2>${n.t}</h2>
<p>${n.tx}</p>
</g:each>
Part of the exception is
Exception Message: No such property: t for class: java.lang.String
How can I make it work?
Thanks
Change
<g:each var="n" in="news">
to
<g:each var="n" in="${news}">
You are iterating over "news" instead of the returned result in the news var.
You should make it work by putting non-UI code in the controller or a service, and passing the data to the views in the model. It's a really bad idea to do database work or other business logic in a GSP/JSP/etc. MVC is about separating concerns.