0

I am new to scala and type-safe languages so I could be overlooking something basic. That said here's my problem.

Goal: I want to submit a form that is just one text input, and does not mirror my case class. It is going to end up as type: String

Issue: Can't get into success from fold

I have a form on the frontend that I opted to write in html instead of play's form helpers (willing to change if this is the issue)

<form method="POST" action="@routes.Application.shorten()">
  <input id="urlLong" name="urlLong" type="text" placeholder="http://www.google.com/" class="span4"/>
  <div class="form-actions">
    <button type="reset" class="btn">Reset</button>
    <button type="submit" class="btn btn-primary pull-right"><span class="icon-random"></span> Shrtn It!</button>
  </div>
</form>

The controller that is handling the post action looks like this:

import ...

object Application extends Controller {

  val newUrlForm = Form(
    "urlLong" -> text
  )

  def shorten = Action { implicit request =>
    val urlLong = newUrlForm.bindFromRequest.get

    newUrlForm.fold(
      hasErrors = { form =>
        val message = "Somethings gone terribly wrong"
        Redirect(routes.Application.dash()).flashing("error" -> message)
    },

    success = { form =>
      val message = "Woot it was successfully added!"
      Redirect(routes.Application.dash()).flashing("success" -> message)
    }
  }
  ...
}

I was trying to follow / modify the tutorial in the Play for Scala book, but they match their form to a case class, and Play's tutorial is a bit off from my use case as well. Along with your answer if you could include how you figured it out, that would be really useful so I can troubleshoot on my own better.

Also if it matters I am using intellij idea as my ide

AKnox
  • 1,965
  • 3
  • 16
  • 19

2 Answers2

1

You need to call the fold method on form.bindFromRequest. From the documentation > Handling binding failure

loginForm.bindFromRequest.fold(
  formWithErrors => // binding failure, you retrieve the form containing errors,
  value => // binding success, you get the actual value 
)

Also you can use the single Mapping construct for a single field

Form(
  single(
    "email" -> email
  )
)
mericano1
  • 2,844
  • 1
  • 15
  • 24
  • Is mapping just a way of converting form names then, or do they serve some other (necessary) purpose ? – AKnox Feb 18 '13 at 20:23
  • yes mappings are a simple way to map from an html form to your own domain objects. In this case it is a single parameter so it doesn't help that much, in fact you should be able to bind directly as shown in [this answer](http://stackoverflow.com/a/9657824/152601). But for more complex scenarios it is very handy indeed – mericano1 Feb 18 '13 at 22:06
0

What I ended up with:

def shorten = Action { implicit request =>
  newUrlForm.bindFromRequest.fold(
    hasErrors = { form =>
      val message = "Somethings gone terribly wrong"
      Redirect(routes.Application.dash()).flashing("error" -> message)
    },

    success = { urlLong =>
      val message = "Woot it was successfully added!"
      Redirect(routes.Application.dash()).flashing("success" -> message)
    }
  )
}

Not sure I really understand what I was doing wrong, but this code based off of mericano1 's answer ended up working as well. It seems like previously i was getting the urlLong val out of the form and then folding the form, where as this folds the form directly, and extracts the val of urlLong in the process.

Also I'm not sure why the arguments for fold are documented differently.

AKnox
  • 1,965
  • 3
  • 16
  • 19
  • I think what you are missing is that `newUrlForm.bindFromRequest` does not do any side effect on `newUrlForm`, it simply returns a new Form object with values bound from the request. So if you fold on `newUrlForm` instead of `newUrlForm.bindFromRequest` values are not available and hence the error (you did not mark the `urlLong` text as optional in your form) – mericano1 Feb 18 '13 at 22:13