質問

I have several CRUD operations to perform, each one on a collection of models (e.g. game schedule, team roster, game result, game stats, etc.).

Up to this point in my Play experience (just a few months, 1 project live) I have been working with one-to-one form binding to model instance.

I know I can numerically index form field names, but then how to bind the posted form to List[Model]?

This is what my one-to-one binding looks like:

// abstract away bindFromRequest to make binding more concise in controllers
def bindForm[T](f: play.api.data.Form[T])(implicit r: play.api.mvc.Request[_]) =
  f.bindFromRequest fold(e=> Left(e.errorsAsJson), Right(_))

and then in controllers:

val result = for {
  model <- bindForm(form).right
  id    <- dao.create(model) as json
} yield id

what I would like to do is the same, but instead of model binding returning a single Model on success, have it return a List[Model], and pass on to overloaded DAO create/edit/delete operations.

I see that there is a list method that one can use as part of a Form mapping, but I have a feeling that that would wreak havoc with my JDBC query wrapper (ScalaQuery/Slick), whose case class/companion object mapping would likely not play well with collections properties.

For example, existing mapping of a game schedule looks like:

object CompositeForm {
  import play.api.data.{Form, Forms}, Forms._
  import utils.Validator.Bindings.jodaLocalTimeFormat
  val mapper = mapping(
    'id   -> ignored(0),
    'gameDate -> jodaDate,
    'gameType -> optional(text),
    'location -> optional(text),
    'team1    -> number,
    'team2    -> number
  )(Composite.apply)(Composite.unapply)
  val form = Form( mapper )
}

using list(gameDate), list(gameType) instead then means that form binding will return a single Composite instance whose properties are all collections -- maybe it will work, but doesn't seem nearly as clean/straightforward as working with a collection of model instances.

Ideas appreciated ;-)

役に立ちましたか?

解決

The as yet documented seq() option in play form mapping was pointed out to me on Play google group by @Julien Richard-Foy

Using repeat() and seq() together allows one to repeat a form mapping, thus creating a collection of indexed foo.bar[n] formfield elements.

Example

object ScheduleForm {
  import play.api.data.{Form, Forms}, Forms._
  val mapper = mapping(
    'composite -> seq(CompositeForm.mapper), 
    'note -> seq(ScheduleNoteForm.mapper)
  )(Schedule.apply)(Schedule.unapply)
  val form = Form( mapper )
}

and then in a view:

@repeat(_form("composite"), min=@numGames) { f=>
    @inputDate(f("gameDate"), '_label-> "Game Date", 'class-> "required")
...
}
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top