## 6.5.3 Flow Execution Events

In order to transition execution of a flow from one state to the next you need some way of trigger an event that indicates what the flow should do next. Events can be triggered from either view states or action states.

#### Triggering Events from a View State

As discussed previously the start state of the flow in a previous code listing deals with two possible events. A `checkout` event and a `continueShopping` event:

    def shoppingCartFlow = {
        showCart {
            on("checkout").to "enterPersonalDetails"
            on("continueShopping").to "displayCatalogue"
        }
        …
    }

Since the `showCart` event is a view state it will render the view `grails-app/book/shoppingCart/showCart.gsp`. Within this view you need to have components that trigger flow execution. On a form this can be done use the submitButton tag:

    <g:form action="shoppingCart">
        <g:submitButton name="continueShopping" value="Continue Shopping"></g:submitButton>
        <g:submitButton name="checkout" value="Checkout"></g:submitButton>
    </g:form>

The form must submit back to the `shoppingCart` flow. The name attribute of each submitButton tag signals which event will be triggered. If you don't have a form you can also trigger an event with the link tag as follows:

    <g:link action="shoppingCart" event="checkout" />

#### Triggering Events from an Action

To trigger an event from an `action` you need to invoke a method. For example there is the built in `error()` and `success()` methods. The example below triggers the `error()` event on validation failure in a transition action:

    enterPersonalDetails {
       on("submit") {
             def p = new Person(params)
             flow.person = p
             if(!p.validate())return error()
       }.to "enterShipping"
       on("return").to "showCart"
    }

In this case because of the error the transition action will make the flow go back to the `enterPersonalDetails` state.

With an action state you can also trigger events to redirect flow:

    shippingNeeded {
       action {
           if(params.shippingRequired) yes()
           else no()
       }
       on("yes").to "enterShipping"
       on("no").to "enterPayment"
    }