tags:

views:

91

answers:

2

I have a Grails WebFlow that is similar to the following example:

def myFlow = {
    init {
        action {
            def domain = MyDomain.get(params.id)
            flow.domain = domain ? domain : new MyDomain()
        }
        on('success').to 'first'
    }

    first {
        on('continue') {
            flow.domain.properties = params
            if(!flow.domain.validate()) {
                return error()
            }
        }.to 'second'
    }

    ...
}

Given this example, if a validation error occurs in the transition on('continue') in first:

  • What's the preferred way to set the model with the invalid domain object so I can use a <g:hasErrors>... in my view (like I would in a normal controller action)?
  • When I call error(), does it send the flow back to init or to first?
  • Does error() take any arguments (i.e. a model) that can be used for what I'm trying to accomplish (I can't find much documentation on the error() method).
  • I'd also take suggestions on how I could improve my flow states to better-facilitate handling these validation errors.

Summary: What's the preferred way to render validation errors within a Grails Web Flow?

A: 

I've found that one way to do it is to specifically invoke render() in the transition state, providing the model. Here's an example where only one field is validated:

first {
    render(view: 'info', model: [flow.domain])
    on('continue') {
        if(!flow.domain.validate(['myField'])) {
            return error()
        }
    }.to 'second'
}

One can then use <g:hasErrors> as follows:

<g:hasErrors bean="${domain}" field="myField">
    <g:renderErrors bean="${domain}" as="list" field="myField"/>
</g:hasErrors>
Rob Hruska
+1  A: 

-1

What's the preferred way to set the model with the invalid domain object so I can use a ... in my view (like I would in a normal controller action)?

You just need to return your domain object that has the errors. you can do that in an action state

action {
  user.validate()
  return [user:user]
}

You can also set your errors in flash scope. On each transition Grails will copy the content of the flash scope into the ModelView and thus available in your gsp page

action {
   flash.error = "your message"
}

-2

When I call error(), does it send the flow back to init or to first? When you call error it call the transition you defined for

You should define a handler for such as

on("error").to("handlerError")

Does error() take any arguments (i.e. a model) that can be used for what I'm trying to accomplish (I can't find much documentation on the error() method).

I don't think so but you can do the following to set any variable when transitioning from one state to another

on("error") {
  // do Something
}.to("handlerError")

3-

I'd also take suggestions on how I could improve my flow states to better-facilitate handling these validation errors.

I use flash for global and form errors but i needed ONE way to deal it. Currently with Grails the flash scope is managed differently in a flow than it's managed in a normal action. So I decided to write a little plugin to change the way the flash scope is handled in a flow and make it consistent with the way is managed in a normal action. I a gsp page i can use my tags in the follwing way regardless of the action type (normal or flow)

    <message:global />
or 
    <message:inline />

As for Form fields errors, i didn't like to deal with errors in domain objects. I wanted something more unified. So I decided to make them part of the http protocol and I have a javascript component the inject them into the form if i opt to. I found this solution much cleaner than dealing with g:errors each time.

-ken

ken
+1, Thanks for the answer. I'll have a look at your suggestions.
Rob Hruska