-
Notifications
You must be signed in to change notification settings - Fork 213
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Play! Forms
- Loading branch information
Showing
10 changed files
with
407 additions
and
1 deletion.
There are no files selected for viewing
94 changes: 94 additions & 0 deletions
94
play-scala/play-templates/app/controllers/FormController.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
package controllers | ||
|
||
import com.google.inject.Inject | ||
import models.{ | ||
ComplexFormCustomField, | ||
InputFormWithConstraints, | ||
MultipleFieldsForm, | ||
SimpleForm | ||
} | ||
import play.api.i18n.I18nSupport | ||
import play.api.libs.json.Json | ||
import play.api.mvc.{ | ||
AbstractController, | ||
Action, | ||
AnyContent, | ||
ControllerComponents | ||
} | ||
|
||
class FormController @Inject() (cc: ControllerComponents) | ||
extends AbstractController(cc) | ||
with I18nSupport { | ||
|
||
def simpleForm: Action[AnyContent] = Action { implicit request => | ||
Ok(views.html.Baeldung.FormTemplate(SimpleForm.form)) | ||
} | ||
|
||
def formPost(): Action[AnyContent] = Action { implicit request => | ||
val form = SimpleForm.form.bindFromRequest().get | ||
Ok(form.toString) | ||
} | ||
|
||
def multipleFieldsForm: Action[AnyContent] = Action { implicit request => | ||
Ok(views.html.Baeldung.MultipleFieldsFormTemplate(MultipleFieldsForm.form)) | ||
} | ||
|
||
def multipleFieldsFormPost(): Action[AnyContent] = Action { | ||
implicit request => | ||
val form = MultipleFieldsForm.form.bindFromRequest().get | ||
Ok(form.toString) | ||
} | ||
|
||
def formWithConstraints: Action[AnyContent] = Action { implicit request => | ||
Ok( | ||
views.html.Baeldung.FormTemplateWithConstraints( | ||
InputFormWithConstraints.form | ||
) | ||
) | ||
} | ||
|
||
def formWithConstraintsPost(): Action[AnyContent] = Action { | ||
implicit request => | ||
InputFormWithConstraints.form | ||
.bindFromRequest() | ||
.fold( | ||
{ formWithError => | ||
BadRequest( | ||
views.html.Baeldung.FormTemplateWithConstraints(formWithError) | ||
) | ||
}, | ||
{ data => Ok(Json.toJson(data)) } | ||
) | ||
} | ||
|
||
def simpleFormPostWithErrors(): Action[AnyContent] = Action { | ||
implicit request => | ||
SimpleForm.form | ||
.bindFromRequest() | ||
.fold( | ||
{ formWithError => | ||
BadRequest( | ||
views.html.Baeldung.FormTemplateWithErrors(formWithError) | ||
) | ||
}, | ||
{ data => Ok(Json.toJson(data)) } | ||
) | ||
} | ||
|
||
def complexForm: Action[AnyContent] = Action { implicit request => | ||
Ok(views.html.Baeldung.ComplexFormTemplate(ComplexFormCustomField.form)) | ||
} | ||
|
||
def complexFormPostWithErrors(): Action[AnyContent] = Action { | ||
implicit request => | ||
ComplexFormCustomField.form | ||
.bindFromRequest() | ||
.fold( | ||
{ formWithError => | ||
BadRequest(views.html.Baeldung.ComplexFormTemplate(formWithError)) | ||
}, | ||
{ data => Ok(Json.toJson(data)) } | ||
) | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,189 @@ | ||
package models | ||
|
||
import models.Measure.UnitMeasurement | ||
import play.api.data.Form | ||
import play.api.data.Forms._ | ||
import play.api.data.validation.Constraints.minLength | ||
import play.api.libs.json.{Json, Writes} | ||
|
||
import java.time.Instant | ||
import java.time.temporal.ChronoUnit | ||
import java.util.{Date, UUID} | ||
|
||
case class SimpleForm(i: Int, active: Boolean, msg: String) | ||
|
||
object SimpleForm { | ||
|
||
implicit val simpleFormWrites: Writes[SimpleForm] = Json.writes[SimpleForm] | ||
val form: Form[SimpleForm] = Form( | ||
mapping( | ||
"i" -> number, | ||
"active" -> boolean, | ||
"msg" -> text | ||
)(SimpleForm.apply)(SimpleForm.unapply) | ||
) | ||
|
||
def unapply(simpleForm: SimpleForm): Option[(Int, Boolean, String)] = { | ||
Some((simpleForm.i, simpleForm.active, simpleForm.msg)) | ||
} | ||
|
||
} | ||
|
||
case class MultipleFieldsForm( | ||
i: Int, | ||
pwd: String, | ||
active: Boolean, | ||
msg: String, | ||
date: Date, | ||
uuid: UUID, | ||
favMovie: String, | ||
favDrink: String | ||
) | ||
|
||
object MultipleFieldsForm { | ||
|
||
implicit val multipleFieldsFormWrites: Writes[MultipleFieldsForm] = | ||
Json.writes[MultipleFieldsForm] | ||
val form: Form[MultipleFieldsForm] = Form( | ||
mapping( | ||
"i" -> number, | ||
"pwd" -> text, | ||
"active" -> boolean, | ||
"msg" -> text, | ||
"date" -> date, | ||
"uuid" -> uuid, | ||
"favMovie" -> text, | ||
"favDrink" -> text | ||
)(MultipleFieldsForm.apply)(MultipleFieldsForm.unapply) | ||
) | ||
|
||
def unapply( | ||
multipleFieldsForm: MultipleFieldsForm | ||
): Option[(Int, String, Boolean, String, Date, UUID, String, String)] = { | ||
Some( | ||
( | ||
multipleFieldsForm.i, | ||
multipleFieldsForm.pwd, | ||
multipleFieldsForm.active, | ||
multipleFieldsForm.msg, | ||
multipleFieldsForm.date, | ||
multipleFieldsForm.uuid, | ||
multipleFieldsForm.favMovie, | ||
multipleFieldsForm.favDrink | ||
) | ||
) | ||
} | ||
|
||
object Movies { | ||
val list = List( | ||
"pulpFiction" -> "Pulp Fiction", | ||
"inception" -> "Inception", | ||
"theMatrix" -> "The Matrix", | ||
"titanic" -> "Titanic" | ||
) | ||
} | ||
|
||
object Drinks { | ||
val list = List( | ||
"vodka" -> "Vodka", | ||
"tequila" -> "Tequila", | ||
"whisky" -> "Whisky", | ||
"wine" -> "Wine", | ||
"beer" -> "Beer" | ||
) | ||
} | ||
|
||
} | ||
|
||
case class ComplexFormCustomField( | ||
i: Int, | ||
active: Boolean, | ||
msg: String, | ||
measurement: UnitMeasurement | ||
) | ||
object ComplexFormCustomField { | ||
|
||
implicit val complexFormWrites: Writes[ComplexFormCustomField] = | ||
Json.writes[ComplexFormCustomField] | ||
val form: Form[ComplexFormCustomField] = Form( | ||
mapping( | ||
"i" -> number, | ||
"active" -> boolean, | ||
"msg" -> text, | ||
"measurement" -> Measure.unitMeasurementMapping | ||
)(ComplexFormCustomField.apply)(ComplexFormCustomField.unapply) | ||
) | ||
|
||
def unapply( | ||
complexForm: ComplexFormCustomField | ||
): Option[(Int, Boolean, String, UnitMeasurement)] = { | ||
Some( | ||
( | ||
complexForm.i, | ||
complexForm.active, | ||
complexForm.msg, | ||
complexForm.measurement | ||
) | ||
) | ||
} | ||
} | ||
|
||
case class InputFormWithConstraints( | ||
i: Int, | ||
msg: String, | ||
msgOpt: Option[String], | ||
email: String, | ||
birthday: Date | ||
) | ||
object InputFormWithConstraints { | ||
|
||
implicit val inputFormWrites: Writes[InputFormWithConstraints] = | ||
Json.writes[InputFormWithConstraints] | ||
val form: Form[InputFormWithConstraints] = Form( | ||
mapping( | ||
"i" -> number(min = 10, max = 20), | ||
"msg" -> text(minLength = 3, maxLength = 12), | ||
"msgOpt" -> optional(text), | ||
"email" -> email, | ||
"birthday" -> date | ||
)(InputFormWithConstraints.apply)(InputFormWithConstraints.unapply) | ||
) | ||
|
||
def unapply( | ||
inputForm: InputFormWithConstraints | ||
): Option[(Int, String, Option[String], String, Date)] = { | ||
Some( | ||
( | ||
inputForm.i, | ||
inputForm.msg, | ||
inputForm.msgOpt, | ||
inputForm.email, | ||
inputForm.birthday | ||
) | ||
) | ||
} | ||
} | ||
|
||
case class InputFormWithCustomConstraints(email: String, birthday: Date) | ||
object InputFormWithCustomConstraints { | ||
|
||
implicit val inputFormWrites: Writes[InputFormWithCustomConstraints] = | ||
Json.writes[InputFormWithCustomConstraints] | ||
val form: Form[InputFormWithCustomConstraints] = Form( | ||
mapping( | ||
"email" -> email.verifying(minLength(15)), | ||
"birthday" -> date.verifying( | ||
"Not 18 years old", | ||
d => d.toInstant.isBefore(Instant.now().minus(18, ChronoUnit.YEARS)) | ||
) | ||
)(InputFormWithCustomConstraints.apply)( | ||
InputFormWithCustomConstraints.unapply | ||
) | ||
) | ||
|
||
def unapply( | ||
inputForm: InputFormWithCustomConstraints | ||
): Option[(String, Date)] = { | ||
Some((inputForm.email, inputForm.birthday)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package models | ||
|
||
import play.api.data.format.{Formats, Formatter} | ||
import play.api.data.{FormError, Forms, Mapping} | ||
import play.api.libs.json.{Json, Writes} | ||
|
||
object Measure { | ||
|
||
def unitMeasurementMapping: Mapping[UnitMeasurement] = | ||
Forms.of[UnitMeasurement] | ||
|
||
case class UnitMeasurement(quantity: Int, unit: String) | ||
|
||
implicit def binder: Formatter[UnitMeasurement] = | ||
new Formatter[UnitMeasurement] { | ||
override def bind( | ||
key: String, | ||
data: Map[String, String] | ||
): Either[Seq[FormError], UnitMeasurement] = Formats.parsing( | ||
d => UnitMeasurement.fromString(d), | ||
"The format is (\\d*)(\\s)(\\D*)- example: \"1 pound\"", | ||
Nil | ||
)(key, data) | ||
|
||
override def unbind( | ||
key: String, | ||
value: UnitMeasurement | ||
): Map[String, String] = Map(key -> s"${value.quantity} ${value.unit}") | ||
} | ||
|
||
object UnitMeasurement { | ||
|
||
implicit val unitMeasurementFormWrites: Writes[UnitMeasurement] = | ||
Json.writes[UnitMeasurement] | ||
|
||
private val pattern = "(\\d*)(\\s)(\\D*)".r | ||
|
||
def fromString(str: String): UnitMeasurement = { | ||
val matches = pattern.findAllIn(str) | ||
if (matches.hasNext) { | ||
val List(number, space, quantity) = matches.subgroups | ||
UnitMeasurement(number.toInt, quantity) | ||
} else { | ||
throw new RuntimeException(s"Incorrect data: $str") | ||
} | ||
} | ||
} | ||
|
||
} |
12 changes: 12 additions & 0 deletions
12
play-scala/play-templates/app/views/Baeldung/ComplexFormTemplate.scala.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
@import helper._ | ||
|
||
@(complexFormCustomField: Form[ComplexFormCustomField])(implicit messages: Messages) | ||
|
||
|
||
@form(action = routes.FormController.complexFormPostWithErrors()) { | ||
@inputText(complexFormCustomField("i")) | ||
@inputText(complexFormCustomField("active")) | ||
@inputText(complexFormCustomField("msg")) | ||
@inputText(complexFormCustomField("measurement")) | ||
<input type="submit" value="Submit"> | ||
} |
10 changes: 10 additions & 0 deletions
10
play-scala/play-templates/app/views/Baeldung/FormTemplate.scala.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
@import helper._ | ||
|
||
@(simpleForm: Form[SimpleForm])(implicit messages: Messages) | ||
|
||
@form(action = routes.FormController.formPost()) { | ||
@inputText(simpleForm("i")) | ||
@inputText(simpleForm("active")) | ||
@inputText(simpleForm("msg")) | ||
<input type="submit" value="Submit"> | ||
} |
13 changes: 13 additions & 0 deletions
13
play-scala/play-templates/app/views/Baeldung/FormTemplateWithConstraints.scala.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
@import helper._ | ||
|
||
@(formWithConstraints: Form[InputFormWithConstraints])(implicit messages: Messages) | ||
|
||
|
||
@form(action = routes.FormController.formWithConstraintsPost()) { | ||
@inputText(formWithConstraints("i")) | ||
@inputText(formWithConstraints("msg")) | ||
@inputText(formWithConstraints("msgOpt")) | ||
@inputText(formWithConstraints("email")) | ||
@inputDate(formWithConstraints("birthday")) | ||
<input type="submit" value="Submit"> | ||
} |
11 changes: 11 additions & 0 deletions
11
play-scala/play-templates/app/views/Baeldung/FormTemplateWithErrors.scala.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
@import helper._ | ||
|
||
@(simpleForm: Form[SimpleForm])(implicit messages: Messages) | ||
|
||
|
||
@form(action = routes.FormController.formPost()) { | ||
@inputText(simpleForm("i")) | ||
@inputText(simpleForm("active")) | ||
@inputText(simpleForm("msg")) | ||
<input type="submit" value="Submit"> | ||
} |
Oops, something went wrong.