Reputation: 1569
I'm trying to update a hasMany
relationship through a form using data binding, but the data I get in my params
doesn't seem correct.
Domain class:
class CustomerSite {
static hasMany = [dhrs:DeviceHistoryRecord];
static mapping = {
id generator:'sequence', params:[sequence:'cs_seq']
}
...
}
Edit view:
...
<g:select name="dhrs" id="dhrs"
from="${DeviceHistoryRecord.list()}"
multiple="multiple"
optionKey="id"
value="${customerSiteInstance?.dhrs}"/>
Controller:
def update = {
def customerSiteInstance = CustomerSite.get( params.id )
if(customerSiteInstance) {
customerSiteInstance.properties = params
String flashMsg = new String();
flash.message = "";
if(!customerSiteInstance.hasErrors() && customerSiteInstance.save()) {
flash.message += "Customer Site ${customerSiteInstance.toString()} updated"
redirect(action:show,id:customerSiteInstance.id)
}
else {
flash.message = flashMsg
render(view:'edit',model:[customerSiteInstance:customerSiteInstance])
}
}
else {
flash.message = "Customer Site not found with id ${params.id}"
redirect(action:edit,id:params.id)
}
}
This gives me an error:
Error 200: org.springframework.beans.NotReadablePropertyException: Invalid property 'currentDeviceData' of bean class [java.lang.String]: Bean property 'currentDeviceData' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
at this line in the controller code:
if(!customerSiteInstance.hasErrors() && customerSiteInstance.save()) {
That doesn't make any sense to me, but I did some fooling with it (a lot, actually), and eventually figured out that the g:select
is passing in a collection of indexes to params.
The view outputs code that I think looks correct:
<select name="dhrs" id="dhrs" multiple="multiple" >
<option value="2421" >801122</option>
<option value="2422" >801123</option>
...
If I were to select items at index 0 and index 1 of the list, it's not passing in a set of "2421" & "2422" like I'd expect. It's passing in "0" & "1". To make matters worse, after I run that, when I go back to the edit page and run it again, this time selecting something at index 8, it's going to have "8"...but also the "0" and "1" from last time.
Looking around here a bit, I found Selecting multiple values from select tag - Grails, which has some other ideas, including making a change like this:
<g:select name="dhrs.id"
from="${DeviceHistoryRecord.list()}"
multiple="multiple"
optionKey="id"
value="${customerSiteInstance?.dhrs*.id}"/>
But that gave me a missing method error, although it did fix the issue of having indexes instead of actual values returned.
Any ideas of what's going on here and how I can fix it?
BTW, I'm running version 1.0.4 of Grails. Yes, I'd love to upgrade it, but I can't.
Thanks!
Upvotes: 0
Views: 1936
Reputation: 1569
I spent more time on this, and got a partial solution. Here's what I ended up with:
<g:select name="dhrsX.id"
from="${DeviceHistoryRecord.list()}"
multiple="multiple"
optionKey="id"
value="${customerSiteInstance?.dhrs*.id}"/>
Notice that's dhrsX
- not dhrs
. That way, I can manually lookup each one before setting them in the CustomerSite
object. The only complication is that if the user selects one item, dhrsX
contains a String
; if the user selects multiple items, dhrsX
contains a list of String
s. To address that, I needed to repackage the selection results before trying to use them directly.
def update = {
def customerSiteInstance = CustomerSite.get( params.id )
if(customerSiteInstance) {
customerSiteInstance.properties = params
customerSiteInstance.dhrs.clear()
for(thisDHR in params.dhrsX) {
def value = thisDHR.getValue()
def ArrayList<String> list = new ArrayList<String>();
if (value instanceof String) {
list.add(value)
} else {
for(oneValue in value) {
list.add(oneValue)
}
}
for(aDHR in list){
DeviceHistoryRecord rec = DeviceHistoryRecord.get(aDHR)
if (rec != null) {
customerSiteInstance.addToDhrs(rec)
} else {
print(thisDHR + " NOT FOUND!")
}
}
}
...
Now single selection and multiple selection work...but there's still a small outstanding issue. Despite calling clear()
on dhrs
before adding the new selections, the prior selections remain. I don't expect this to be nearly as complicated to fix, however.
Upvotes: 1
Reputation: 919
In the g:select use:
value="${customerSiteInstance?.dhrs?.id}"
Questionmark instead of star. This is how I have my "multiselects".
Upvotes: 0