hasErrors with indexed property - grails

I am having hard time getting hasErrors to work with indexed properties. For example
class Order {
String prop1
String prop2
static hasMany = [items: Item]
}
class Item {
String name
static constraints = {
name(blank:false)
}
}
Validation works properly and on item.name being blank I do get an error with
<g:renderErrors bean="${orderInstance}"/>
However, I am trying to have input box highlighted using hasErrors :
<g:each in="${orderIntsance.items}" status="i" var="item">
<span class="field ${hasErrors(bean: orderInstance, field: ????????? , 'errors')}">
<g:textField name="items[${i}].name" value="${item?.name}"/>
</span>
</g:each>
Not sure how to get to it with a field: property, any ideas?
Thanks

Found it, got to implement a custom validator per Grails Validation doc page (duh):
"In some situations (unusual situations), you might need to know how to transfer an error from a nested child object to a parent domain object. In some circumstances, if you validate the children objects before the parent object, then the errors on the children objects will get reset before the object is sent to the JSP." (http://www.grails.org/Validation)
static constraints = {
children( nullable:true, validator: {val, obj, errors ->
def errorFound = false;
val.each{ child ->
if(!child .validate()){
errorFound = true;
child .errors.allErrors.each{ error->
obj.errors.rejectValue('children', "parent.child.invalid",
[child, error.getField(), error.getRejectedValue()] as Object[],
"For source [${child}],
field [${error.getField()}] with value [${error.getRejectedValue()}] is invalid.")
}
}
}
if(errorFound) return false;
})
}

I had a similar requirement and tried the following way and it worked. Just wanted to share it
${hasErrors(bean: orderInstance, field: 'items['+ i +'].name', 'errors')

Related

Formatting POJO inside Grails/GSP select element

I have the following POJO/POGO:
class Person {
String firstName
String lastName
int age
// ... lots of other fields
}
And a Grails 2.3.6 controller:
class PeopleController {
List<Person> people = new ArrayList<Person>()
def populatePeople() {
// Add lots of people to the 'people' list.
}
def doSomething() {
populatePeople()
render(
view: "people",
model:[
people: people,
]
)
}
}
And then in the GSP:
<div id="peopleSelector">
<g:select name="people" from="${people}" />
</div>
When I run my app I get the <select> element with com.me.myapp.domain.Person#398r4d99-looking values as <option>s. This is obviously Grails not deserializing my Person instances into pretty print form.
I want peoples' first and last names to appear as the select options. Hence, if one of the Person instances in the people list is:
Person smeeb = new Person(firstName: "Smeeb", lastNname: "McGuillocuty")
Then I would expect "Smeeb McGuillocuty" as a select option in the final HTML. How can I accomplish this?
Add the following method to your Person class:
#Override public String toString() {
"$firstName $lastName"
}
And, somewhat unrelated to the actual question, you may have to add an identifier to your option rows to uniquely identify the person. Assuming the Person class has an id property:
<g:select name="people" from="${people}" optionKey="id" />
so that you get the following HTML:
<select name="people" id="people">
<option value="123">Smeeb McGuillocuty</option>
:
Useful link to official doc: http://grails.org/doc/latest/ref/Tags/select.html:
"..The default behaviour is to call toString() on each element in the from attribute.."
If you can't/won't "sacrifice" toString() for rendering in HTML you can also tell the g:select how to render the options. Either by providing the name of a property in optionValue (e.g. optionValue="fullName" and then provide a String getFullName() method (watch out for transients, if you pass a GORM object)) or by providing it directly in the GSP:
<g:select name="person" optionKey="theId" optionValue='${{"$it.lastName, $it.firstName"}}' from="${people}" />

grails select box Cannot cast String to List

I have the following in a select box
<div class="form-group">
<label for="machinename">Portails</label>
<select name='portalsChoice' multiple class="form-control">
<g:each in="${portals}" var="portal">
<option>${portal.name}</option>
</g:each>
</select>
</div>
Then, in a controller, I get all parameter like this :
def mymethod() {
List<String> portalsChoice = params.portalsChoice
...
}
If I select 2 elements, it works well.
I I select only 1 element, I have the following error : Cannot cast object 'my string' with class 'java.lang.String' to class 'java.util.List'
What is the best way to avoid this error ?
Thanks in advance,
Replace this
def mymethod() {
List<String> portalsChoice = params.portalsChoice
}
with
def mymethod() {
List<String> portalsChoice = params.list('portalsChoice')
}
The portalsChoice list will contain the selected elements, regardless of how many were selected.
You can provide a check in your controller:
List<String> portalsChoice = []
if(params.portalsChoice instanceof String){
//force it to be a list
portalsChoice = params.list('portalsChoice')
}else{
//for multiple
portalsChoice = params.portalsChoice
}
not so tricky but helps resolve your issue.

GORM: populate list into select dropdown

I am working on a Grails form item that just populates a list of FaqCategories from an FaqCategory domain class. All I want the select dropdown to do is display the list. So far, this sort of works, but I'm not sure how to generate the list or what to put in the Value section if anything.
Form item:
<div class="col-sm-9">
<g:select name="Category" from="${FaqCategory.list()}" required="" class="form-control" aria-labelledby="faqCategory-label" value=""/>
</div>
Domain class #1
class Faq {
String question
String answer
FaqCategory faqCategory
static constraints ={
question nullable:false, maxSize:1000
answer nullable:false, maxSize:1000
faqCategory nullable:false
}
}
Domain class #2
class FaqCategory {
String categoryType
String toString(){
"$categoryType"
}
static constraints = {
categoryType nullable:true, maxSize:100, unique:true
}
}
Controller snippet
#Transactional(readOnly = true)
def create() {
respond new Faq(params)
}
Controller code :
yourAction(int id){
//do some
def faqInstance = Faq.get(id)
render[view:"form",model:[faqInstance:faqInstance]]
}
View code :
<g:select name="faqCategory"
from="${FaqCategory.list()}"
value="${faqInstance?.faqCategory?.categoryType}"
optionKey="id" />
Hope it helps..
You haven't provided enough information to show the context in which this select is being used so it is hard to say exactly what you need, but something like this should work:
<g:select name="faqCategory"
from="${FaqCategory.list()}"
value="${you only need this if you want to preselect a value}"
optionKey="id" />
See http://grails.org/doc/latest/ref/Tags/select.html for more details.
I hope that helps.

Grails form creation for many-to-one belongsTo

I am a beginner in grails and I have a basic question. I want to display a list of instances of a parent class in the child class form creation.
My Domain class are as follows. The Parent class is the Company.
class Company {
String name
static constraints = {
name(blank:false)
}
String toString(){name}
}
My Child Class is the Location of the company.
class Location {
String name
String address
static belongsTo= {companyLocation:Company}
static constraints = {
name(blank: false)
address blank:false
}
String toString(){"company:"+companyLocation+"Location:"+name}
}
Now in the _form template' of location view I have the code for thecompanyLocation dropdown`
<div class="fieldcontain ${hasErrors(bean: locationInstance, field: 'companyLocation', 'error')} required">
<label for="companyLocation">
<g:message code="location.companyLocation.label" default="companyLocation" />
<span class="required-indicator">*</span>
<g:select id="companyLocation" name="companyLocation.id" from="${first_project.Company.list()}" optionKey="id" required="" value="${locationInstance?.companyLocation?.id}" class="many-to-one"/>
</label>
</div>
When I go to the the create page I get the error:
Error 500: Internal Server Error
URI /first_project/location/create
Class groovy.lang.MissingPropertyException
Message No such property: companyLocation for class: first_project.Location
Why am I getting this error when I have a static variable companyLocation defined in the Location Domain class? Could some please let me know where I have gone wrong?
Thanks in advance.
This looks like a syntax issue,
static belongsTo= {companyLocation:Company}
should really be
static belongsTo= [companyLocation:Company]
There is one more OO method of doing this, instead of using has many and belongs to...
create another CompanyLocation Domain class.
Class CompanyLocation {
Company company
Location location
static constraints = {
company(blank:false, nullable:false)
location(blank:false, nullable:false)
}
public String toString() {
return "${company} ${location}"
}
}

How to validate Domain Classes correctly when Properties are HTML Encoded in Grails?

I use html encoding for my form input fields. I have a form to create a new user object, where one can insert a name for the new user. To prevent this input field from script injection I do encodeAsHTML() in the save() action listed below.
The problem:
1. the entered name is: Schäfchen
2. this would be validated correctly after my validation rules below
3. html encoding transform ä into \auml which will fail the validation
How can I achieve that the name which in html encoded will be correctly validated?
Given the following Grails class:
class User {
String name
static constraints = {
name blank: false, validator: { val, obj ->
Pattern pattern = Pattern.compile("[a-zA-Z0-9äöüßÄÖÜ\\- ]+")
pattern.matcher(val).matches()
}
}
}
in my UserController.groovy:
dev save() {
def name = params?.name?.encodeAsHTML()
def user = new User()
user.name = name
user.save()
}
You should use encodeAsHTML() only in your GSP views.
See: http://grails.org/doc/latest/ref/Tags/each.html
<tbody>
<g:each status="i" in="${itemList}" var="item">
<!-- Alternate CSS classes for the rows. -->
<tr class="${ (i % 2) == 0 ? 'a' : 'b'}">
<td>${item.id?.encodeAsHTML()}</td>
<td>${item.parentId?.encodeAsHTML()}</td>
<td>${item.type?.encodeAsHTML()}</td>
<td>${item.status?.encodeAsHTML()}</td>
</tr>
</g:each>
</tbody>

Resources