Todd Sjolander
Todd Sjolander

Reputation: 1569

Grails select tag results

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

Answers (2)

Todd Sjolander
Todd Sjolander

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 Strings. 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

Tom Metz
Tom Metz

Reputation: 919

In the g:select use:

value="${customerSiteInstance?.dhrs?.id}"

Questionmark instead of star. This is how I have my "multiselects".

Upvotes: 0

Related Questions