Get BigDecimal value from Grails params - grails

I am writing a reporting functionality for a Domain object in grails. There is field "balance" which is BigDecimal. I am having trouble writing the query. Appreciate any help.
View
<tr class="prop">
<td valign="top" class="name">
<label for="balance"><g:message code="sale.balance.label" default="Balance" /></label>
</td>
<td valign="top" class="value">
<g:textField name="balance" value="${params.balance}" />
</td>
</tr>
Controller
def c = Sale.createCriteria()
def saleList = c.list {
if(params.id)
idEq(java.lang.Long.parseLong(params.id))
if(params.customerName)
like('customerName', params.customerName+"%")
if(params.customerPh)
like('customerPh', params.customerPh+"%")
if(params.balance)
ge('balance', java.math.BigDecimal(params.balance))
if(params.totalSale)
ge('totalSale', params.totalSale)
Exception
groovy.lang.MissingPropertyException: No such property: java for class: grails.orm.HibernateCriteriaBuilder
at colorthread.SaleController$_closure9_closure23.doCall(SaleController.groovy:289)
at colorthread.SaleController$_closure9_closure23.doCall(SaleController.groovy)

You are missing the new keyword:
ge('balance', new java.math.BigDecimal(params.balance))

Related

Create dynamic table with webflow and grails

I'm trying to create a webflow with a dynamic table on one page. Which looks like this
def startFlow = {
contact {
on('next') {
flow.developer = params.developer
flow.project = params.project
flow.division = params.division
flow.projectResponsible = params.projectResponsible
flow.email = params.email
[flow : flow]
}.to('ipcount')
on('cancel').to('finish')
}
ipcount{
on('next'){
flow.ipcount = params.int('ipcount')
[flow: flow]
}.to('systems')
on('cancel').to('finish')
}
systems{
on('next') {
flow.hoster= params.hoster
flow.ip = params.ip
flow.os = params.os
flow.dns = params.dns
flow.systemDate = params.systemDate
[flow : flow]
}.to('url')
on('cancel').to('finish')
} ....
The problem is I that the number of systems could be different every time (1...n).
One idea was to ask the page before how many entries should be created (ipcount).
My view looks like this
<g:set var="count" value="${flow.ipcount}" />
<g:each in="${(1..'${count}')}">
<tr class="prop">
<td valign="top" class="name">
<label for="ip">IP Adresse:</label>
</td>
<td valign="top">
<td valign="top" class="value ${hasErrors(bean:hosterInstance,field:'ip','errors')}">
<input type="text" id="ip" name="ip" value="${params.ip}" />
</td>
<td valign="top" class="name">
<label for="dns">DNS:</label>
</td>
<td valign="top">
<input type="text" id="dns" name="dns" value="${params.dns}" />
</td>
<td valign="top" class="name">
<label for="os">Operating System:</label>
</td>
<td valign="top">
<input type="text" id="dns" name="dns" value="${params.os}" />
</td>
</tr>
</g:each>
Beside that this is not working as I get an Internal server error: (java.lang.String cannot be cast to java.lang.Integer) it would be nicer if I could at the table row dynamically on the page.
Here is the question: Is this possible with webflow and how? Especially I don't know how to handle the flow parameter and how to save the collected entries at the end of the webflow to the database.
If you need to work with a list of objects, command objects is the way to go. It supports databinding from the incoming request and will handle lists.
You can check a related question that show's you how to do it.
And in your view, you will need to handle the index in the name of your input. Example:
Consider
class System {
String ip
String dns
...
}
And commandInstance.systems a List<System>.
<g:each in="${commandInstance.systems}" var="command" status="i">
<input type="text" id="ip$i" name="systems[$i].ip" value="${command.ip}" />
</g:each>

Grails upload image

I am trying to upload a picture, and save it in database.
If I do the following I get this error:
Failed to convert property value of type
org.springframework.web.multipart.commons.CommonsMultipartFile to
required type java.lang.Byte[] for property picture1; nested exception
is java.lang.IllegalArgumentException: Cannot convert value of type
[org.springframework.web.multipart.commons.CommonsMultipartFile] to
required type [java.lang.Byte] for property picture1[0]:
PropertyEditor
[org.springframework.beans.propertyeditors.CustomNumberEditor]
returned inappropriate value
If i do it this way:
if(request instanceof MultipartHttpServletRequest){
MultipartHttpServletRequest mpr = (MultipartHttpServletRequest)request;
CommonsMultipartFile f = (CommonsMultipartFile) mpr.getFile("picture1");
}
I get this error:
Executing action [save] of controller [com.testapp.RequestController]
caused exception: Cannot cast object '
org.springframework.web.multipart.commons.CommonsMultipartFile#34ae1f02'
with class
'org.springframework.web.multipart.commons.CommonsMultipartFile' to
class 'java.lang.Byte'
What should I do to make this work?
Domain
package com.testapp
class Request{
String requestID
Date dateCreated
String subject
String startedBy
String description
String status
String priority
Productline productline
Topic topic
Subtopic subtopic
String company
Byte [] picture1
Byte [] picture2
Byte [] picture3
String acceptedBy
static constraints = {
requestID(blank:true,nullable:true)
dateCreated(blank:true,nullable:true)
subject()
description(maxSize:5000)
status (blank:true,nullable:true)
priority(inList:["Normal","Urgent","Not urgent"])
productline(blank:true,nullable:true)
topic(blank:true,nullable:true)
subtopic(blank:true,nullable:true)
company(blank:true,nullable:true)
startedBy(blank:true,nullable:true)
acceptedBy(blank:true,nullable:true)
picture1(blank:true,nullable:true)
picture2(blank:true,nullable:true)
picture3(blank:true,nullable:true)
}
}
GSP:
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="layout" content="main" />
<g:set var="entityName" value="${message(code: 'request.label', default: 'Request')}" />
<title><g:message code="New request" args="[entityName]" /></title>
</head>
<body>
<div class="nav">
<span class="menuButton"><a class="home" href="${createLink(uri: '/')}"><g:message `code="default.home.label"/></a></span>`
<span class="menuButton"><g:link class="list" action="userList"><g:message code="Lista zahteva" `args="[entityName]" /></g:link></span>`
</div>
<div class="body">
<h1><g:message code="New request" args="[entityName]" /></h1>
<g:if test="${flash.message}">
<div class="message">${flash.message}</div>
</g:if>
<g:hasErrors bean="${requestInstance}">
<div class="errors">
<g:renderErrors bean="${requestInstance}" as="list" />
</div>
</g:hasErrors>
<g:form action="save" method="post" enctype="multipart/form-data">
<div class="dialog">
<table>
<tbody>
<tr class="prop">
<td valign="top" class="name">
<label for="subject"><g:message code="request.subject.label" default="Subject" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: requestInstance, field: 'subject', 'errors')}">
<g:textField name="subject" value="${requestInstance?.subject}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="description"><g:message code="request.description.label" default="Opis" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: requestInstance, field: 'description', 'errors')}">
<g:textArea name="description" cols="40" rows="5" value="${requestInstance?.description}" />
</td>
</tr>
<tr>
<td valign="top" class="name">
<label for="picture1"><g:message code="request.picture1.label" default="Printscreen" /></label>
</td>
<td valign="top" class="value">
<input type="file" id="picture1" name="picture1"/>
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="priority"><g:message code="request.priority.label" default="Priority" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: requestInstance, field: 'status', 'errors')}">
<g:select name="priority" from="${requestInstance.constraints.priority.inList}" value="${requestInstance?.priority}" valueMessagePrefix="request.priority" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="productline"><g:message code="request.productline.label" default="Productline" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: requestInstance, field: 'productline', 'errors')}">
<g:select name="productline.id" from="${com.testapp.Productline.list()}" optionKey="id" value="${requestInstance?.productline?.id}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="topic"><g:message code="request.topic.label" default="Topic" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: requestInstance, field: 'topic', 'errors')}">
<g:select name="topic.id" from="${com.testapp.Topic.list()}" optionKey="id" value="${requestInstance?.topic?.id}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name">
<label for="subtopic"><g:message code="request.subtopic.label" default="Subtopic" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: requestInstance, field: 'subtopic', 'errors')}">
<g:select name="subtopic.id" from="${com.testapp.Subtopic.list()}" optionKey="id" value="${requestInstance?.subtopic?.id}" />
</td>
</tr>
</tbody>
</table>
</div>
<div class="buttons">
<span class="button"><g:submitButton name="create" class="save" value="${message(code: 'default.button.create.label', default: 'Create')}" /></span>
</div>
</g:form>
</div>
</body>
Controller:
def save = {
def requestInstance = new Request(params)
def requestNumberInstance = new RequestNumber()
def upPic1 = request.getFile('picture1')
def lastReqNum = RequestNumber.find("from RequestNumber ORDER BY requestNumber desc")
if(lastReqNum){
requestNumberInstance.requestNumber = lastReqNum.requestNumber + 1
}
else{
requestNumberInstance.requestNumber = 110000
}
requestInstance.requestID = "CSC" + requestNumberInstance.requestNumber
def currentUserContact = Contact.findByUser(springSecurityService.getCurrentUser())
requestInstance.startedBy = currentUserContact.realname
requestInstance.company = currentUserContact.company
requestInstance.status = "Opened"
requestInstance.acceptedBy = "Not yet accepted"
requestInstance.picture1 = upPic1
if(requestNumberInstance.save()){
if (requestInstance.save()) {
flash.message = "${message(code: 'default.created.message', args: [message(code: 'request.label', default: 'Request'), requestInstance.id])}"
redirect(action: "show", id: requestInstance.id)
}
else {
render(view: "create", model: [requestInstance: requestInstance])
}
}
else{
render(view: "create", model: [requestInstance: requestInstance])
}
}
Please dont mind the spaghetti code. I'm just trying to get some basic concepts. I will clear it later.
Simplified example:
def save = {
def requestInstance = new Request(params)
def requestNumberInstance = new RequestNumber()
if(requestInstance.validate() && requestInstance.save(flush: true)){
println "Saved successfully with ${requestInstance.picture1.length} bytes"
}
else {
println "Save failed"
}
Update after question edit
The error is probably caused by this:
def upPic1 = request.getFile('picture1')
...
requestInstance.picture1 = upPic1
request.getFile() is returning a MultipartFile, and you're trying to assign it to a Byte[] field. Considering my small example (below), you shouldn't even need to try to make this assignment. The def requestInstance = new Request(params) will bind the byte[] automatically.
Uploaded files bind automatically to byte[] fields. Here's a working example:
Domain: grails-app/domain/my/Example.groovy
package my
class Example {
byte[] file
}
Controller: grails-app/controllers/my/ExampleController.groovy
package my
class ExampleController {
def create = { }
def save = {
def example = new Example(params)
if(example.validate() && example.save(flush: true)) {
println "Saved successfully with ${example.file.length} bytes"
} else {
println "Save failed"
}
redirect(action: 'create')
}
}
GSP: grails-app/views/example/create.gsp
<!DOCTYPE html>
<html>
<body>
<g:uploadForm action="save">
<input type="file" name="file"/>
<g:submitButton name="submit"/>
</g:uploadForm>
</body>
</html>
When I upload a small file using the GSP form, I see the following console output:
Saved successfully with 23 bytes
Suggestions
Try using Grails data binding to save your file contents.
Make sure your form is a <g:uploadForm> or has an enctype="multipart/form-data" if you're using a vanilla`.
Make sure you're binding the params using the domain constructor, domain.properties, or bindData().
I am guessing your typing is messed up.
What happens if you simply do:
def f = request.getFile('myFile')
as described in the manual. If you want strong typing it should be MultiPartfile, not CommonsMultiPartFile, as far as I remember (and you get it right from the request object).
This is the interface you're working on: http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/multipart/MultipartFile.html
The relevant method for you, should be getBytes().
Edit for edited question:
As I said, you want getBytes(), you are trying to shove a MultiPartFile into a byte array, thats not going to work.
requestInstance.picture = upPic.getBytes() and you should be allright.
It only worked when I changed my domain properties picture1,picture2,picture3 to:
byte [] picture1
byte [] picture2
byte [] picture3
and added those mappings:
static mapping = {
picture1 column:"picture1", sqlType: "blob"
picture2 column:"picture2", sqlType: "blob"
picture3 column:"picture3", sqlType: "blob"
}

MVC Model with multiple HttpPostedFileBase properties

I'm using the following model with my get/post actions.
Public Class AuthorEditQuestionViewModel
<Required()>
<Display(Name:="Question Title")>
Public Property Title As String
<Display(Name:="Start Ledger")>
Public Property StartLedger As HttpPostedFileBase
Public Property StartLedgerUrl As String
<Display(Name:="End Ledger")>
Public Property EndLedger As HttpPostedFileBase
Public Property EndLedgerUrl As String
<Required()>
<Display(Name:="Introduction/Instructions")>
Public Property IntroductionHtml As String
End Class
The html for the ledger fields is as follows.
<input type="file" id="StartLedger" name="StartLedger" />
<input type="file" id="EndLedger" name="EndLedger" />
However, in the post action, it seems that both the StartLedger and EndLedger properties seem to be populated with the same value (the first file).
Does anyone have any examples of handling multiple named file upload fields with MVC3? It really feels like supporting file uploads well has been a shortcoming in ASP.Net MVC since version 1.
---- EDIT (.vbhtml below)
#Using Html.BeginForm("EditQuestion", "Author", Nothing, FormMethod.Post, New With {.enctype = "multipart/form-data"})
#Html.ValidationSummary("Please correct the following issues.")
#<table class="form">
<tr>
<td class="label">#Html.LabelFor(Function(m) m.Title)</td>
<td class="input">
#Html.TextBoxFor(Function(m) m.Title)
</td>
</tr>
<tr>
<td class="label">#Html.LabelFor(Function(m) m.StartLedger)</td>
<td class="input">
<input type="file" id="StartLedger" name="StartLedger" />
#If Not String.IsNullOrWhiteSpace(Model.StartLedgerUrl) Then
#Download
End If
</td>
</tr>
<tr>
<td class="label">#Html.LabelFor(Function(m) m.EndLedger)</td>
<td class="input">
<input type="file" id="EndLedger" name="EndLedger" />
#If Not String.IsNullOrWhiteSpace(Model.EndLedgerUrl) Then
#Download
End If
</td>
</tr>
<tr>
<td class="label" colspan="2">#Html.LabelFor(Function(m) m.IntroductionHtml)</td>
</tr>
<tr>
<td class="input" colspan="2">#Html.TextAreaFor(Function(m) m.IntroductionHtml, 10, 80, Nothing)</td>
</tr>
<tr>
<td class="buttons" colspan="2">
<button class="action" data-action="#Url.Action("Index")">Cancel</button>
<button>Save</button>
</td>
</tr>
</table>
End Using
The signature for the action is as follows...
Function EditQuestion(id As Guid?, model As AuthorEditQuestionViewModel) As ActionResult

how to select first value in select tag empty(not null) in GSP?

Here is my domain class Incident
class Incident {
String status
Usergroup assignmentGroup
static hasMany={usergroups:Usergroup}
}
I want to find all incidents by assignmentGroup.I am using GORM criteria for this
this is searchIncident.gsp
<tr class="prop">
<td valign="top" class="name">
<label for="assignmentGroup"><g:message code="incident.assignmentGroup.label" default="Assignment Group" /></label>
</td>
<td valign="top" class="value ${hasErrors(bean: incidentInstance, field: 'assignmentGroup', 'errors')}">
<g:select id="groupSelect" name="assignmentGroup.id" from="${app.Usergroup.list()}" optionKey="id" value="" />
</td>
</tr>
<tr class="prop" >
<td valign="top" class="name">
<label for="status"><g:message code="incident.status.label" default="Status" /></label>
</td>
<td valign='top' class='value'>
<g:select name='status' from='${[""] + new Incident().constraints.status.inList}'>
</g:select>
</td>
</tr>
In my option tag i must select the first value empty(not null).
If I've understood, you need to include the noSelection attribute, as in:
// use a no selection with a nullable Object property (use 'null' as key)
<g:select id="type" name='type.id' value="${person?.type?.id}"
noSelection="${['null':'Select One...']}"
from='${PersonType.list()}'
optionKey="id" optionValue="name"></g:select>
See the grails docs here for more: http://grails.org/doc/latest/ref/Tags/select.html
Jim

Saving object having many-to-many relationship in grails

I am trying to save objects having Many-Many Relationship . A SellingCompany can have many Accounts and an Account can be associated with many SellingCompanies. So there is a many-many relationship between the tables stored in SellingCompaniesAccount
My Account_Info domain is as follows:
class AccountInfo {
static mapping ={
table 'AccountInfo'
version false
//id column:'accountInfoID'
}
String evi_pass_phrase
String evi_username
String security_key
// to make sure fields show up in a particular order
static constraints = {
//accountInfoID(insert:false,update:false)
evi_pass_phrase()
evi_username()
security_key()
}
static hasMany = [sellingcompaniesaccount:SellingCompaniesAccount]
String toString() {
return "${evi_username}"
}
}
My SellingComapanies domain is as follows:
class SellingCompanies
{
static mapping = {
table 'SellingCompanies'
version false
}
String name
//static belongsTo = AccountInfo
//static hasMany = [accounts: AccountInfo]
static hasMany = [sellingcompaniesaccount:SellingCompaniesAccount]
static constraints = {
name(blank:false, validator:
{ val, obj ->
def similarSellingCompanies = SellingCompanies.findByNameIlike(val)
return !similarSellingCompanies || (obj.id == similarSellingCompanies.id)
})
}
//String toString() { name }
}
The table that holds the Many-Many relationship is as follows:
class SellingCompaniesAccount {
static constraints = {
// ensure the group of sellingCompaneis and accountInfo values are unique
agency_name(unique:['sellingCompanies','accountInfo'])
}
int agency_id
String agency_name
String consultant_id
String code
Boolean isActive
String iata
ContactInfo contactinfo
static belongsTo = [sellingCompanies:SellingCompanies, accountInfo:AccountInfo]
}
}
The form in the create.gsp file contains the code that actually iterates over all the different SellingCompanies and displays as a check-box.
<g:form action="save" method="post">
<div class="dialog">
<table width="500px" border="0px" color="red">
<tbody>
<tr class="prop">
<td valign="top" class="name"><label for="accountInfo"><g:message
code="sellingCompaniesAccount.accountInfo.label"
default="Account Info" /></label></td>
<td valign="top"
class="value ${hasErrors(bean: sellingCompaniesAccountInstance, field: 'accountInfo', 'errors')}">
<g:select name="accountInfo.id"
from="${content_hub_admin.AccountInfo.list()}" optionKey="id"
value="${sellingCompaniesAccountInstance?.accountInfo?.id}" /></td>
</tr>
<tr class="prop">
<td valign="top" class="name"><label for="sellingCompanies"><g:message
code="sellingCompaniesAccount.sellingCompanies.label"
default="Selling Companies" /></label></td>
<td valign="top"
class="">
<g:each in="${content_hub_admin.SellingCompanies.list()}" var="item" status="i">
${++i}. ${item.name} <g:checkBox name="sellingcompanies_${++i-1}" optionKey="id" value="${item.id}" /> <br>
</g:each>
<!-- end here by rsheyeah -->
</td>
</tr>
<tr class="prop">
<td valign="top" class="name"><label for="code"><g:message
code="sellingCompaniesAccount.code.label" default="Code" /></label></td>
<td valign="top"
class="value ${hasErrors(bean: sellingCompaniesAccountInstance, field: 'code', 'errors')}">
<g:textField name="code"
value="${sellingCompaniesAccountInstance?.code}" /></td>
</tr>
<tr class="prop">
<td valign="top" class="name"><label for="agency_name"><g:message
code="sellingCompaniesAccount.agency_name.label"
default="Agencyname" /></label></td>
<td valign="top"
class="value ${hasErrors(bean: sellingCompaniesAccountInstance, field: 'agency_name', 'errors')}">
<g:textField name="agency_name"
value="${sellingCompaniesAccountInstance?.agency_name}" /></td>
</tr>
<tr class="prop">
<td valign="top" class="name"><label for="isActive"><g:message
code="sellingCompaniesAccount.isActive.label" default="Is Active" /></label>
</td>
<td valign="top"
class="value ${hasErrors(bean: sellingCompaniesAccountInstance, field: 'isActive', 'errors')}">
<g:checkBox name="isActive"
value="${sellingCompaniesAccountInstance?.isActive}" /></td>
</tr>
<tr class="prop">
<td valign="top" class="name"><label for="agency_id"><g:message
code="sellingCompaniesAccount.agency_id.label" default="Agencyid" /></label>
</td>
<td valign="top"
class="value ${hasErrors(bean: sellingCompaniesAccountInstance, field: 'agency_id', 'errors')}">
<g:textField name="agency_id"
value="${fieldValue(bean: sellingCompaniesAccountInstance, field: 'agency_id')}" />
</td>
</tr>
<tr class="prop">
<td valign="top" class="name"><label for="iata"><g:message
code="sellingCompaniesAccount.iata.label" default="Iata" /></label></td>
<td valign="top"
class="value ${hasErrors(bean: sellingCompaniesAccountInstance, field: 'iata', 'errors')}">
<g:textField name="iata"
value="${sellingCompaniesAccountInstance?.iata}" /></td>
</tr>
<tr class="prop">
<td valign="top" class="name"><label for="consultant_id"><g:message
code="sellingCompaniesAccount.consultant_id.label"
default="Consultantid" /></label></td>
<td valign="top"
class="value ${hasErrors(bean: sellingCompaniesAccountInstance, field: 'consultant_id', 'errors')}">
<g:textField name="consultant_id"
value="${sellingCompaniesAccountInstance?.consultant_id}" /></td>
</tr>
<tr class="prop">
<td valign="top" class="name"><label for="contactinfo"><g:message
code="sellingCompaniesAccount.contactinfo.label"
default="Contactinfo" /></label></td>
<td valign="top"
class="value ${hasErrors(bean: sellingCompaniesAccountInstance, field: 'contactinfo', 'errors')}">
<g:select name="contactinfo.id"
from="${content_hub_admin.ContactInfo.list()}" optionKey="id"
value="${sellingCompaniesAccountInstance?.contactinfo?.id}" /></td>
</tr>
</tbody>
</table>
</div>
<div class="buttons"><span class="button"><g:submitButton
name="create" class="save"
value="${message(code: 'default.button.create.label', default: 'Create')}" /></span>
</div>
</g:form>
Lastly the controller which handles the save and list functions.
class SellingCompaniesAccountController {
private static Logger log = Logger.getLogger(SellingCompaniesAccountController.class)
//def index = { }
//def scaffold = true
def index = { redirect(action:list,params:params) }
//To limit access to controller actions based on the HTTP request method.
def allowedMethods = [save:'POST']
//create.gsp exists
def create = {
render(view:"create")
}
//edit.gsp exists
//def edit = {}
//list.gsp exists
def list = {
[ sellingCompaniesAccountInstanceList: SellingCompaniesAccount.list( max:15) ]
}
//show.gsp exists
//def show={}
//save.gsp exists
def save = {
log.info "Saving: " + params.toString()
println("Saving: " + params.toString())
def sellingCompaniesAccount = params.sellingCompaniesAccount
println(sellingCompaniesAccount)
def sellingCompanies = params.sellingCompanies
log.info "sellingCompanies: " + sellingCompanies
println(sellingCompanies)
def sellingCompaniesAccountInstance = new SellingCompaniesAccount(name: params.name)
println(params.name)
params.each {
if (it.key.contains("_sellingcompanies"))
//sellingCompaniesAccountInstance.sellingCompaniesId << SellingCompanies.get((it.key - "sellingcompanies_") as Integer)
if (it.key.contains("sellingcompanies_"))
sellingCompaniesAccountInstance.sellingCompaniesId << SellingCompanies.get((it.key - "sellingcompanies_") as Integer)
}
log.info sellingCompaniesAccountInstance
if (sellingCompaniesAccountInstance.save(flush: true)) {
flash.message = "${message(code: 'default.created.message', args: [message(code: 'sellingCompaniesAccountInstance.label', default: 'sellingCompaniesAccountInstance'), sellingCompaniesAccountInstance.id])}"
redirect(action: "show", id: sellingCompaniesAccountInstance.id)
log.info sellingCompaniesAccountInstance
}
else {
render(view: "create", model: [sellingCompaniesAccountInstance: sellingCompaniesAccountInstance])
}
}
}
Now, I am getting the following error, due to the empty hidden values appearing like _sellingcompanies_1 etc.:
Error Logs:
Saving: ["accountInfo.id":"1", "accountInfo":["id":"1"], "_sellingcompanies_5":"", "_isActive":"", "code":"test", "agency_name":"test", "sellingcompanies_4":"4", "sellingcompanies_5":"5", "create":"Create", "isActive":"on", "iata":"test", "agency_id":"test", "contactinfo.id":"1", "contactinfo":["id":"1"], "consultant_id":"test", "sellingcompanies_2":"2", "_sellingcompanies_1":"", "sellingcompanies_3":"3", "_sellingcompanies_2":"", "_sellingcompanies_3":"", "sellingcompanies_1":"1", "_sellingcompanies_4":"", "action":"save", "controller":"sellingCompaniesAccount"]
null
null
null
2011-03-15 17:13:44,620 [http-8080-2] ERROR org.codehaus.groovy.grails.web.errors.GrailsExceptionResolver - For input string: "_5"
java.lang.NumberFormatException: For input string: "_5"
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:449)
at java.lang.Integer.valueOf(Integer.java:554)
at content_hub_admin.SellingCompaniesAccountController$_closure4_closure5.doCall(content_hub_admin.SellingCompaniesAccountController:70)
at content_hub_admin.SellingCompaniesAccountController$_closure4.doCall(content_hub_admin.SellingCompaniesAccountController:66)
at content_hub_admin.SellingCompaniesAccountController$_closure4.doCall(content_hub_admin.SellingCompaniesAccountController)
at java.lang.Thread.run(Thread.java:680)
First of all, where does the hidden values come from and is this approach fine to commit the the Many-Many relationship info in SellingCompaniesAccount controller class. Any better technique of doing this.
The create.gsp resolves to this in the browser:
Thanks in advance
If anyone else is having the same problem then the above answer by Daniel is absolutely correct just adding few changes as of Grails 2.7.8.
All checkbox will have same value = "${item.id}" and name ="sellingcompanies" as shown below:
<!-- ... snip ... -->
<tr class="prop">
<td valign="top" class="name"><label for="sellingCompanies"><g:message
code="sellingCompaniesAccount.sellingCompanies.label"
default="Selling Companies" /></label></td>
<td valign="top"
class="">
<g:each in="${content_hub_admin.SellingCompanies.list()}" var="item" status="i">
${++i}. ${item.name} <g:checkBox name="sellingcompanies" optionKey="id" value="${item.id}" /> <br>
</g:each>
<!-- end here by rsheyeah -->
</td>
</tr>
<!-- ... snip ... -->
Best part is that in present version of Grails you wont need to use flatten() as string as mentioned by Daniel and these values will automatically be handled by Grails and will be persisted in the join table. All you need to be sure is your checkbox have correct name and value.
Hope it helps!
The problem is with this piece of code:
params.each {
if (it.key.contains("_sellingcompanies"))
//sellingCompaniesAccountInstance.sellingCompaniesId << SellingCompanies.get((it.key - "sellingcompanies_") as Integer)
if (it.key.contains("sellingcompanies_"))
sellingCompaniesAccountInstance.sellingCompaniesId << SellingCompanies.get((it.key - "sellingcompanies_") as Integer)
}
Your params from the form post are:
Saving: ["accountInfo.id":"1", "accountInfo":["id":"1"], "_sellingcompanies_5":"", "_isActive":"", "code":"test", "agency_name":"test", "sellingcompanies_4":"4", "sellingcompanies_5":"5", "create":"Create", "isActive":"on", "iata":"test", "agency_id":"test", "contactinfo.id":"1", "contactinfo":["id":"1"], "consultant_id":"test", "sellingcompanies_2":"2", "_sellingcompanies_1":"", "sellingcompanies_3":"3", "_sellingcompanies_2":"", "_sellingcompanies_3":"", "sellingcompanies_1":"1", "_sellingcompanies_4":"", "action":"save", "controller":"sellingCompaniesAccount"]
The test in your loop first checks if the parameter key contains "_sellingcompanies" and then it does nothing; the second part of that checks if the parameter key contains "sellingcompanies_" and then it tries to pull the suffixed number off of that parameter value. In the case of a parameter with the key value "_sellingcompanies_5", both the first test and the second test evaluate to true, so in the second test, you are subtracting the "sellingcompanies_" off of the parameter key value and you are left with "_5", which you are then trying to evaluate to an Integer. Unfortunately, "_5" is not a valid Integer value, and hence your given error.
You can solve this very simply by doing the following:
params.each {
if (it.key.startsWith("sellingcompanies")) {
sellingCompaniesAccountInstance.sellingCompaniesId << SellingCompanies.get((it.key - "sellingcompanies_") as Integer)
}
}
Probably a better way to handle this though would be to change your gsp to give the same named parameter for each of the sellingcompanies, and then looping through the actual applied values. Something like this:
<!-- ... snip ... -->
<tr class="prop">
<td valign="top" class="name"><label for="sellingCompanies"><g:message
code="sellingCompaniesAccount.sellingCompanies.label"
default="Selling Companies" /></label></td>
<td valign="top"
class="">
<g:each in="${content_hub_admin.SellingCompanies.list()}" var="item" status="i">
${++i}. ${item.name} <g:checkBox name="sellingcompanies" optionKey="id" value="${item.id}" /> <br>
</g:each>
<!-- end here by rsheyeah -->
</td>
</tr>
<!-- ... snip ... -->
Then in your controller do something like this:
params.sellingcompanies = [params.sellingcompanies].flatten() as String[]
sellingCompaniesAccountInstance.sellingCompaniesId = params.sellingcompanies.collect { SellingCompanies.get(it) }
This should ensure that you are properly evaluating the appropriate values that have been passed from your model object, and not hacking in a retrieval method.
Hope this helps!

Resources