Unclosed GSP expression: Grails GSP engine does not resolve nested GSP expression - grails

I need to create a custom gsp whose domain model is designed as follows
class Question {
SortedSet<Choice> choiceCollection;
static hasMany = [choiceCollection:Choice]
static mappping = {
choiceCollection(joinTable:false)
}
}
Each Question object has five Choices. So, i create the following snippet of code
create.gsp
<g:each var="i" in="${(1..5)}">
<div class="fieldcontain required">
<label for="description">
Option ${i}.
<span class="required-indicator">*</span>
</label>
<g:textArea name="choiceCollection[${i}].description" cols="40" rows="5" maxlength="2000" value="${questionInstance?.choiceCollection[${i}]?.description}"/>
</div>
</g:each>
Although Grails GSP engine complains Unclosed GSP expression which is not true - g:textArea is closed as you can see above -, i believe the real problem is the expression
${questionInstance?.choiceCollection[${i}]?.description}
which involves nested GSP expressions.
Question: am i missing some feature ? If so, what should i do to overcome my obstacle ?
Grails version: 2.1.1

Shouldn't
${questionInstance?.choiceCollection[${i}]?.description}
be
${questionInstance?.choiceCollection[ i ]?.description}
The set bit:
Try something like:
<g:each var="choice" status="i" in="${questionInstance?.choiceCollection}">
So i still contains your index, but choice contains what you were trying to get with questionInstance?.choiceCollection[${i}]

Related

displaying bean class items on view - beginner

The bean class looks like this:
String houseNo
String address
Person person
The view looks like this
<g:form action="save">
<fieldset class="form">
<g:render template="form" />
</fieldset>
<fieldset class="buttons">
<g:submitButton name="create" class="save"
value="${message(code: 'default.button.create.label', default: 'Create')}" />
</fieldset>
</g:form>
According to my knowledge in Grails, i think is <g:render template="form" /> will pull all form attributes and display it.
But what i want to do is Instead of displaying a drop-down for Person, i want to display all Person related fields like personName, personAge. How can i display these fields in a label underneath ?
Help
You're correct about the way g:render works, the template part refers to a GSP which will look through the bean values and print them according to the html + groovy markup in "_form.gsp" (located in your views folder under the controller name).
To change the way the Person domain object is displayed, simply edit this "_form.gsp" and take out the 'select' html code - replacing it with groovy markup using the property values of the bean, eg.
${beanName.person.personName} //(use the existing code to help workout the bean name etc)
Hopefully that helps you on your way.

How can I use g:render with my g:each variable from a Map collection?

I have a def statusMap = HashMap<String, List<MyItem>>() that gets passed into my gsp page.
In my gsp page I have the following:
<g:each var="myList" in="${statusMap}">
<div id="pending_list" class="onTop">
<g:render template="/list" model="['list':"${myList.value}", 'listSize':"${myList.value.size()}"]" />
</div>
</g:each>
But I can't seem to correctly pass myList.value and myList.value.size() into my template. I think my quotes are wrong somehow but I'm not sure.
How can I correctly pass myList.value and myList.value.size() into the list template through the model?
Since you are using a map your itteration is based on keys within that Map. So the basic syntax looks like this:
<g:each in=${yourCoolMap.entrySet()}" var="entry">
${entry.key} = ${entry.value}
</g:each>
Thus, your code will look something like this:
<g:each var="myList" in="${statusMap.entrySet()}">
<div id="pending_list" class="onTop">
<g:render template="/list" model="['list': myList.value, 'listSize': myList.value.size()]" />
</div>
</g:each>

Grails Field Plugin: Select tag for one-to-many relationships

I'm using Grails 2.2.3 and Fields plugin 1.3.
I want to customize fields to manage one-to-many relationships using select tag.
In views/_fields/oneToMany/_input.gsp I have:
<g:select name="${property}.id" from="${type.list()}" optionKey="id" value="${value}" class="form-control one-to-many" noSelection="['null': "${label}"]" />
But type is a set, so I can't use list function.
How can I retrieve target domain class?
As long as you use a Map to declare the relationship, for example:
static hasMany = [ books: Book ]
You can get the list of the referenced domain, which is the key from the hasMany property of the bean, so the from attribute should change to
from="${bean.hasMany[property].list()}"
Alternatively you can pass the list to the _input.gsp template prefixing the variable name with input-, e.g.
<f:field property="books" input-domainList="${bookInstaceList}" />
In the _input.gsp template you can use the variable as follows:
from="${domainList}"
or mixing both methods:
from"${domainList ?: bean.hasMany[property].list()}"
I found this solution for the problem, this code work fine with one to many and one to one
<div class="input-group">
<g:select name="${persistentProperty.toString().contains('one-to-many')?property:property+'.id'}" value="${value?.id}" required="${required}"
noSelection="${['null':'Escriba...']}" class="select2 col-md-6"
multiple="${persistentProperty.toString().contains('one-to-many')?true:false}" from="${grailsApplication.getDomainClass(persistentProperty.properties['associatedEntity'].toString()).clazz.list()}"
optionKey="id"></g:select>
</div>
This solution can be helpful. I found in the documentacion of Fields Plugin, the persistentProperty is a class type DomainProperty but their methods doesn't works and I found the correct class is org.grails.datastore.mapping.model.MappingFactory
you can use .toArray() method on your Set instead of .list().
ale
You can use the code below to identify the Element of your collection
def className = bean.hasMany[property].properties.typeName
See my "views/_fields/oneToMany/_input.gsp" implementation:
<%# page defaultCodec="html" %>
<%
def className = bean.hasMany[property].properties.typeName
def simpleName = Class.forName(className).simpleName
def beanSimpleName = bean.class.simpleName
def createUri = "/${simpleName.toLowerCase()}/create?${beanSimpleName.toLowerCase()}.id=${bean.id}"
%>
<a id="add${simpleName}" name="add${simpleName}" href="${createLink(uri: "${createUri}")}">
Add ${simpleName}
</a>
<ul>
<g:each var="item" in="${value}">
<li>
${item}
</li>
</g:each>
</ul>

Grails populate g:select from database

I ran into an issue while populating domain object values on a gsp page by using a g:select tag.
<g:select name="demo" id="demo"
value="${dm.id}"
noSelection="${['null':'Select..']}"
from="${dm}"
optionValue="${dm.type}"/>
In my controller, I have an object which gathers values from my domain. I tried writing this object in the controller both as:
def d = Demo.getAll()
and def d = Demo.list()
Both of these returned an exception while trying to use the g:select tag. The error was:
No signature of method: Demo.getAt() is applicable for argument types: (java.util.ArrayList) values: [[One, Two, Three, Four, Five]]
I was able to get my code working by simply removing the g:select tag and writing the following in my gsp:
<select name="demo" id="dm">
<option value="">Select!</option>
<g:each in="${dm}" status="i" var="dm">
<option value="${dm.id}">${dm.name}</option>
</g:each>
</select>
However, I would like to know how to make this work with the g:select tag, for my future reference.
Thanks in advance!
I see two issues in your select:
<g:select name="demo" id="demo"
value="${dm.id}"
noSelection="${['null':'Select..']}"
from="${dm}"
optionValue="${dm.type}"/>
value shouldn't be looking at the collection for the id. I believe this is why you are getting your error. value should be whatever instance's id you've passed into your view.
optionValue doesn't required an expression.
Controller action
def someAction() {
def dm = Demo.get(params.id)
def demos = Demo.list()
[dm: dm, demos: demos]
}
view
<g:select name="demo" id="demo"
value="${dm.id}"
noSelection="${['null':'Select..']}"
from="${demos}"
optionValue="type"/>

Updating many instances in one view

I'm starting with Grails and I don't know how should I face the following use case.
The app is about sports results prediction, so I have in my domain "Match" and "Prediction", and I want to have one view where the user can update all the predictions of matches that haven't been played yet.
So far I've defined a method in my "PredictionController" that searches all the already existing predictions of games that have to be played and generates new Prediction instances for any new Match with a date higher than now. I've created a view for that method and I'm getting correctly all the predictions that I should complete or update, and I've defined in my controller another method for the form sumbission (so I'm trying to resolve this in the same way that the 'create' and 'update' scaffolded methods work).
My question is, How can I access to all the Predictions modified by my view? How can I send all the predictions to my update method? Is it defining a hidden field with a variable containing all the collection?
This is the form in my GSP view:
<g:form action="savePredicctions">
<fieldset>
<g:each in="${predictions}">
<li>
<div>
${it.match.homeTeam}
<g:field name="${it.match}.homeGoals" type="number" value="${it.homeGoals}" />
</div>
-
<div>
<g:field name="${it.match}.awayGoals" type="number" value="${it.awayGoals}" />
${it.match.awayTeam}
</div>
</li>
</g:each>
</fieldset>
<fieldset class="submit">
<g:submitButton />
</fieldset>
</g:form>
You can use a command object to store the instances of Prediction.
#Validateable
class PredictionCommand {
//data binding needs a non-null attribute, so we use ListUtils.lazyList
List<Prediction> predictions = ListUtils.lazyList([], FactoryUtils.instantiateFactory(Prediction))
}
In your view, you need to control the index of your list, and send the attributes of Prediction to the controller:
<g:each in="${predictions}" status="i">
<g:textField name="predictions[$i].homeGoals" />
<g:textField name="predictions[$i].awayGoals" />
</g:each>
And in your controller you can use bindData() to bind params to your command:
class CommandController {
def save() {
PredictionCommand command = new PredictionCommand()
bindData(command, params)
println command.predictions
}
}

Resources