Michael
Michael

Reputation: 11

Playframework [Scala]: Creating forms

I'm beginner to Scala and Playframework. I have some code in Java and I have a problem to translate it into Scala. Can you suggest something how can I do it? I check documentation about ScalaForms but still I can't understand how to do it. My code is as following:

// Injecting FormFactory     
public Result create(){
  Form<Book> bookForm = formFactory.form(Book.class);
  return ok(create.render(bookForm));
}

public Result save(){
  Form<Book> bookForm = FormFactory.form(Book.class).bindFromRequest();
  Book book = bookForm.get();
  Book.add(book);
  return redirect(routes.BooksController.index());
}

Ok so I have something like this:

  def index = Action {
    val books: Set[Book] = Book.allBooks
    Ok(views.html.index(books))
  }

def create = Action{
    Ok(views.html.create())
  }

  def save = Action {
    implicit request =>
      val (id, title, price, author) = bookForm.bindFromRequest.get
      Book.addBook(id = id, title = title, price = price, author = author)
      Redirect(routes.BooksController.index())
  }

My routes:

GET     /books                      controllers.BooksController.index
GET     /books/create               controllers.BooksController.create
POST    /books/create               controllers.BooksController.save

And the problem is with Redirect, I have an error: "object java.lang.ProcessBuilder.Redirect is not a value"

Upvotes: 1

Views: 134

Answers (1)

o-0
o-0

Reputation: 1799

Ok so for Scala version of dealing with form, this is what I do:

  1. You use bindFromRequest to do, most of the times, two things: 1. If there is an error within the form return it back to the user and 2. If there is no error within the form, use the given data by the user to do some other operations (e.g., call a third party API, or internal API, etc.)

  2. If things are fine (second sub step of the above first step), I return an HTTP response to the user.

So, I would have something like this in my controller method:

def save() = Action {
  implict request => 
  bookForm.bindFromRequest.fold(
    formWithErrors => {
       BadRequest(views.html.whateverTheViewIs(bookForm))
    }, formData => 
       //Do whatever you need to do 
       Ok("saved")//Again, here you can use any views; and pass the required parameters. 
  ) 
} 

It might be the case, that you have difficulty on defining the bookForm itself, so in Scala, you first define your data model using a case class. Lets define a very simple one:

case class Book(title: String, author: String, isbn: String)

Then you define your form:

val bookForm = Form(     
   mapping(
       "title": String -> NonEmptyText
       "author" : String -> NonEmptyText
       "isbn" : String   -> NonEmptyText    
   )(Book.apply)(Book.unapply) 
)

Note on Redirection: For the redirect, as you mentioned in the comment, you could use the URL used. For example ,if I have:

GET /confirmation      controllers.Book.confirmation (bookId: String)

Then I want to redirect to the confirmation URL, knowing that I need to also provide the `userId', I can do the following:

val bookId = "1" //You need to get the Id, from a database or an API.
Redirect(s"/confirmation?bookId=$bookId")

Further Step [Use Future API]: The important thing here is that, for simplicity; I did not use the Future API, for asynchronously respond to the request. This should be your aim, because you want to write non-blocking response, especially if you want to call other APIs, for processing/storing the form's valid input.

Upvotes: 1

Related Questions