Question

I have a form, where user can enter many records of the same domain class. Each of these records should be validated after the submission. In case of successful validation the collection of records should be passed to another view, otherwise validation errors should be displayed in the same view preserving previously entered values. Validation should be done using dedicated command object.

To make better picture, form roughly looks like this: enter image description here

I came up with a solution to map each record to a form (items list is returned from the initial action rendering the view):

<g:each in="${items}" var="item">
    <g:render template="orderItem" model="[item: item]"/>
</g:each>

And the template:

<form>
    ...
    <g:textField value="${item.url}" name="url"></g:textField>
    ...
</form>

But I'm not sure about the correctness of this approach.

When implementing this scenario I faced few challenges:

  1. Is there a better way to map each record instance to the row of fields in the view so that a row of fields would represent one record?
  2. How to pass and validate the whole collection in one call to controller action?

Thanks in advance.

Was it helpful?

Solution

You can do that using command objects. They're validateable objects that can handle a list of domain instances. Example:

Command

import org.apache.commons.collections.ListUtils
import org.apache.commons.collections.Factory

@Validateable
class ItemsCommand {
  List<Item> items = ListUtils.lazyList([], {new Item()} as Factory)
}

GSP

In your view you just need one form. When you create your fields, use the index like:

<g:each in="${command.items}" var="item" status="i">
  <g:textField name="items[$i].url" value="${item.url}" />
  ...
</g:each>

Controller

//this is the submit action, the command will have the Item 
//instances though Data Binding.
def myAction(ItemsCommand command) {
}

Related SO question.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top