Grails retrieve controller parameters in g:each

346 views Asked by At

I am attempting to pass the result of validation failure from a form to a new view, where the fields which failed validation will be displayed. My code keeps displaying an error message instead of the validationResult, which does appear in the url parameters.

The method which checks the validation is as follows:

def confirmFormToSave() {
    def ticket = Ticket.get(params.ticketId)
    def ticketId = params.ticketId as long
    ValidationResult validationResult = ticketService.validateCurrentTicketForms("", ticketId)
    if (!ticketValidationResult.isPassed()) {
      log.error "Validation failure, cannot change Ticket status"
      redirect(action: 'validateForm', params: [id: params.ticketId, validationResult: validationResult])
      return
    } else {
      params.isGroup = false
      redirect(action: 'submitForm', params: params)
    }
  }

This redirects on validation failure to the following method which renders the gsp:

def validateForm() {
    def ticket = Ticket.get(params.ticketId)
    def ticketId = params.ticketId as long
    ValidationResult validationResult = ticketService.validateCurrentTicketForms("", ticketId)
    def message = 'Sorry, we could not change the ticket state, validation has failed, please fill out all required fields.'
      [ticket: ticket, message: message, validationResult: validationResult]
  }

My to pull this back in the gsp is as follows:

<g:each in="${validationResult}" var="resultError">
   <li>${resultError}</li>
</g:each>

I am unsure if I am passing the parameters between the two methods properly, because at the moment I am essentially checking for the same result twice in order to render this in validateForm.gsp, which doesn't seem right.

1

There are 1 answers

0
albertovilches On

I see some strange things in your code:

1) You are using a redirect instead a forward or a direct method call. A http redirect is just a 3xx response code with a Redirect header to the browser with the new url. Your browser will detect the response code, read the Redirect header and it will load the new page with a new http request. More info: https://en.wikipedia.org/wiki/URL_redirection

So, the params map you are using in the redirect will be transformed in a url like that: validateForm?id=WHATEVER&validationResult=WHATEVER, transforming the validationResult object in a String and I guess you don't want to do that because you need an iterable object in your model to loop it with the <g:each> tag. That's the reason you have to do the validation again in the validateForm action.

You shouldn't use a redirect when you have objects (or whatever) in your action if you are going to need them in your model.

2) In your confirmToSave action you are loading a Ticket entity from database, but this variable is not used in your code (it's not a big deal)

3) You are sending an "id" param in your redirect params map but you are getting a "ticketId" param in the validateForm action.

My recommendation is rendering the validateForm gsp from the confirmFormSave directly without a redirect, something like that:

def confirmFormToSave(Long tickectId) {    
    ValidationResult validationResult = ticketService.validateCurrentTicketForms("", ticketId)
    if (!ticketValidationResult.isPassed()) {
      log.error "Validation failure, cannot change Ticket status"
      String message = 'Sorry, we could not change the ticket state, validation has failed, please fill out all required fields.'
      Ticket ticket = Ticket.get(ticketId)
      return render(view: "validateForm", model: [ticket: ticket, message: message, validationResult: validationResult])
    } else {
      params.isGroup = false
      redirect(action: 'submitForm', params: params)
    }
  }