OlivierBlanvillain
OlivierBlanvillain

Reputation: 7768

Play forms: how to fill a repeated field?

I have a form with a repeated field:

case class MyForm(topics: List[Int])
val myForm: Form[MyForm] = Form(
  mapping(
    "topics" -> list(number)
  )(MyForm.apply _)(MyForm.unapply _)
)

And the corresponding view:

@form(...) {
  <h2>Topics of interest:</h2>
  @for(Topic(id, name, _) <- Topics.all) {
    @checkbox(
      bidForm(s"topics[$id]"),
      '_label -> (name + ":").capitalize,
      'value -> id.toString)
  }
  <input type="submit" id="submit" value="Save">
}

So far so good, if there is an error in the field and I re-render it passing myForm.bindFromRequest.

I would like to pre fill the form with data from my database. With other types of fields (number, text, option() and so on) I am able to populate an existingMyForm with something like this:

val existingMyForm = myForm.fill(MyForm(
  // Queries the database and return a list of case classes with field id: Int
  Topics.of(member).map(_.id)
))

However with list this approach fails and I have to manually do the mapping:

val existingMyForm = myForm.bind(
  Topics.of(member).map(t => ("topics[%s]".format(t.id), t.id.toString)).toMap
)

Is there a better way to do this?

Upvotes: 2

Views: 1294

Answers (1)

josephpconley
josephpconley

Reputation: 1723

I believe you need to explicitly pass a List[Int] to the MyForm constructor, i.e.

val existingMyForm = myForm.fill(MyForm(
    Topics.of(member).map(_.id).toList
))

EDIT - Here is my basic implementation which worked for Play 2.1.1 Scala:

case class MyForm(topics: List[Int])
case class Topic(id: Int)
val myForm: Form[MyForm] = Form(
  mapping("topics" -> list(number))(MyForm.apply _)(MyForm.unapply _)
)

val topicList:List[Topic] = List(Topic(1), Topic(2), Topic(3))

def test = Action { implicit req =>
  val existingMyForm = myForm.fill(MyForm(
    topicList.map(_.id)
  ))
  Ok(views.html.test(existingMyForm))
}

Upvotes: 1

Related Questions