haxx qua non

Groovy (Grails) markup builder for select/option menu

by jja on
Topics:

I was trying to use the Groovy XML MarkupBuilder to have Grails output an HTML fragment for an AJAX call and just couldn't get it to work. I wanted to generate an HTML select/option menu from a list of lists:

assert results == [[null,null], [17, 'foo'], [42, 'bar'], [69, 'bahz']]

(That list was returned from a Hibernate Criteria Builder with some specialized projections.)

First I tried to do it simply, following Grails docs:

render {
  select(size:10) {
    results.each {
      if (it[0] && it[1])
        option( value:it[0], it[1] )
      }
    }
  }

I kept getting a blank list. Eventually I figured out that the Grails GSP select tag was interfering with the markup builder DSL, so I tried using that, with list access code in a closure in a GString expression:

render {
  g.select from:results, optionKey:"${{it[0]}}", optionValue:"${{it[1]}}"
  }

Except that both expressions are in the same block and share it. So we have to use different explicit closure parameters:

render {
  g.select from:results, optionKey:"${{itk -> itk[0]}}", optionValue:"${{itv->itv[1]}}"
  }

but that fails with an error like:

`No signature of method: java.io.StringWriter.getAt() is applicable for
argument types: (java.lang.Integer) values: [0] Possible solutions:
getAt(java.lang.String)`

so I tried making the indices into strings:

render {
  g.select from:results, optionKey:"${{itk -> itk['0']}}", optionValue:"${{itv->itv['1']}}"
  }

which resulted in the error:

No such property: 0 for class: java.io.StringWriter

The Grails docs give the example

optionValue="${{it.title?.toUpperCase()}}"

which makes it seem like real code is available. But the itk/itv closure parameters apparently aren't really the list values, which would happily accept the Groovy magic Object.getAt() method. Something like this seemed to work:

render { builder ->
  builder.select(size:10,onchange:"myJsFunc(this);") {
  results.each {
    if (it[0] && it[1])
      option( value:it[0], it[1] )
    }
  }
}

If you're in Grails (and not just straight Groovy), really try to use a view for this!

(comments are closed)