play2 form

play.api.data.Form

Controller中使用:
创建实体:

Scala代码   收藏代码
  1. case class User(username: String,realname: Option[String],email: String)  

 

创建Form对象

Scala代码   收藏代码
  1. val userForm = Form(  
  2.  mapping(  //制定验证规则  
  3.   "username" -> nonEmptyText(8),  
  4.   "realname" -> optional(text),  
  5.   "email" -> email)(User.apply)(User.unapply))  
  6.   
  7. def createUser() = Action { implicit request =>  
  8.  userForm.bindFromRequest.fold(  
  9.   formWithErrors => BadRequest, //有错误的情况 得到的还是一个Form 可以通过getErrors获得错误  
  10.   user => Ok("User OK!"))       //没有错误的情况 得到的是一个User对象  
  11. }  

 


fold的返回值是play.api.mvc.SimpleResult 是BadRequest和Ok的祖先

表格的Mapping 做binding(绑定)和unbinding的操作
把数据放入Form中叫做绑定
Forms是不可变的 binding之后返回一个新的拷贝

一个mapping是一个Mapping[T]对象
以上的代码中 Forms.nonEmptyText 创建了一个Mapping[String] email创建了一个Mapping[String] 更多的Forms.number创建了一个Mapping[Int]
更多的:

  • boolean:       Mapping[Boolean]
  •  checked(msg:  String):    Mapping[Boolean]
  •  date:       Mapping[Date]
  •  email:       Mapping[String]
  •  ignored[A](value:  A):     Mapping[A]
  •  longNumber:      Mapping[Long]
  •  nonEmptyText:      Mapping[String]
  •  number:       Mapping[Int]
  •  sqlDate:       Mapping[java.sql.Date]
  •  text:       Mapping[String]

 


 


form helper:


可以手动写name和mapping中的对应就好了要获取form内的值用data属性就可以了 dataMap对象
也可以借助helper:

 

Html代码   收藏代码
  1. @(productForm: Form[Product])  
  2. @main("Product Form") {  
  3.  @helper.form(action = routes.GeneratedForm.create) {  
  4.   @helper.inputText(productForm("name"))  
  5.   @helper.textarea(productForm("description"))  
  6.   @helper.inputText(productForm("ean"))  
  7.   @helper.inputText(productForm("pieces"))  
  8.   @helper.checkbox(productForm("active"))  
  9.   <div class="form-actions">  
  10.    <button type="submit">Create Product</button>  
  11.   </div>  
  12.  }  
  13. }  

 


会自动生成html 如果要自定义提示信息 查看一下trait Constraints Scaladoc

helper的input:
 inputDate   —Generates an input  tag with type date.
 inputPassword  —Generates an  input  tag with type password .
 inputFile   —Generates an input  tag with type file.
 inputText   —Generates an input  tag with type text.
 select   —Generates a select tag.
 inputRadioGroup  —Generates a set of input  tags with type  radio .
 checkbox    —Generates an  input  tag with type checkbox .
 textarea    —Generates a textarea  element.
 input    —Creates a custom input.
可以增加自定义的属性:

Html代码   收藏代码
  1. @helper.inputText(productForm("name"), '_class -> "important",  
  2. 'size -> 40)  

'size和'_class是symbol类型的
更多的属性:
 _label —Use to set a custom label
 _id   —Use to set the id attribute of the dl element
 _class —Use to set the class attribute of the dl element
 _help  —Use to show custom help text
 _showConstraints —Set to false to hide the constraints on this field
 _error   —Set to a Some[FormError]  instance to show a custom error
 _showErrors  —Set to false to hide the errors on this field

自定义input:

Html代码   收藏代码
  1. @helper.input(myForm("mydatetime")) { (id, name, value, args) =>  
  2.  <input type="datetime" name="@name"  
  3.  id="@id" value="@value" @toHtmlArgs(args)>  
  4. }  

 

第二个参数接受的是一个函数 参数是(String,String,Option[String],Map[Symbol,Any])
(toHtmlArgs来自play.api.templates.PlayMagic)


生成自定义的html:
在views.helper中(也可以是其他包啦 在views下面方便一点) 建立

myFileConstructor.scala.html
写入自定义html:

Html代码   收藏代码
  1. @(elements: helper.FieldElements)  
  2. <div id="@(elements.id)_field" class="clearfix @if(elements.hasErrors) {text-error}">  
  3.     <label for="name">@elements.label</label>  
  4.     <div class="input">  
  5.        @elements.input  
  6.         <span class="help-inline">@elements.errors.mkString(", ")</span>  
  7.     </div>  
  8. </div>  

 
第一个参数是helper.FieldElements 别忘了
然后再建立一个object:

Scala代码   收藏代码
  1. package views.html.helper  
  2. object myHelper {  
  3.   implicit val fieldConstructor = new FieldConstructor {  
  4.     def apply(elements: FieldElements) =  
  5.       myFileConstructor(elements)  
  6.   }  
  7. }  

 
最后在需要的html中导入即可:
@import helper.myHelper._
原本就有一个是twitter的:
import helper.twitterBootstrap._*


 

自定义约束

为Mapping[T]增加约束可以使用verifying(constraints:Constraint[T *)方法( play.api.data.validation.Constraints)
使用如下:"name" -> text.verifying(Constraints.nonEmpty)
自定义约束用verifying实现也很简单 只要向里面传入一个T => Boolean方法即可
例如:
def eanExists(ean: Long) = Product.findByEan(ean).isEmpty
在mapping中:
"ean" -> longNumber.verifying(eanExists(_))
或者简写:
"ean" -> longNumber.verifying(Product.findByEan(_).isEmpty)
也可以带一个错误信息当作第一个参数:
"ean" -> longNumber.verifying("This product already exists.",
Product.findByEan(_).isEmpty)


 

验证多个域:

因为mapping所得的也是个Mapping[T]所以写起来很简单:

Scala代码   收藏代码
  1. val productForm = Form(mapping(  
  2.  "ean" -> longNumber.verifying("This product already exists!",Product.findByEan(_).isEmpty),  
  3.  "name" -> nonEmptyText,  
  4.  "description" -> text,  
  5.  "pieces" -> number,  
  6.  "active" -> boolean)(Product.apply)(Product.unapply).verifying(  
  7.  "Product can not be active if the description is empty",  
  8.  product =>  
  9.   !product.active || product.description.nonEmpty))  

 


这样写有一个问题 错误信息将不会自动生成 因为顶层的Mapping在html中没有id
要自己手动生成 顶层的Mapping产生的错误在Form中是globalError:

Html代码   收藏代码
  1. @productForm.globalError.map { error =>  
  2.  <span class="error">@error.message</span>  
  3. }  

 


 

option可选的:

Scala代码   收藏代码
  1. case class Person(name: String, age: Option[Int])  
  2. val personMapping = mapping(  
  3.  "name" -> nonEmptyText,  
  4.  "age" -> optional(number) //用optional会返回Mapping[Option[T]]  
  5. )(Person.apply)(Person.unapply)  

 


list
:

如果tags是个List可以写成:
"tags" -> list(text) 他将返回Mapping[List[T]]
如果是手动写的话可以写成:
<input type="text" name="tags[0]">
<input type="text" name="tags[1]">
<input type="text" name="tags[2]">
用helper的话 用repeat方法:

Html代码   收藏代码
  1. @helper.repeat(form("tags"), min = 3) { tagField =>  
  2.  @helper.inputText(tagField, '_label -> "Tag")  
  3. }  

tuple and mapping methods take a maximum of  18  parameters.


嵌套:

Scala代码   收藏代码
  1. val appointmentMapping = tuple(  
  2.  "location" -> text,  
  3.  "start" -> tuple(  
  4.  "date" -> date,  
  5.  "time" -> text),  
  6.  "attendees" -> list(mapping(  
  7.  "name" -> text,  
  8.  "email" -> email)(Person.apply)(Person.unapply))  
  9. )  

 


返回的是:
Mapping[(String,(Date, String),List[Person])]

 


自定义Mapping

除了tuple(返回tuples)和mapping(返回对象) 自定义一个:
改变一个现有的(transform)
新建一个

转换类似于后处理:
 如果你有一个Mapping[A] 也有一个A=>B 那可以用transform得到Mapping[B]

Scala代码   收藏代码
  1. val localDateMapping = text.transform(  
  2. (dateString: String) =>  
  3.  LocalDate.parse(dateString),  
  4. (localDate: LocalDate) =>  
  5.  localDate.toString)  

 
不过这样的话 要注意parse可能抛出异常

新建一个formatter
play.api.data.format.Formatter
要实现Formatter[T]的方法:

Scala代码   收藏代码
  1. trait Formatter[T] {  
  2.  def bind(key: String, data: Map[String, String]):Either[Seq[FormError], T]  
  3.    
  4.  def unbind(key: String, value: T): Map[String, String]  
  5.    
  6.  val format: Option[(String, Seq[Any])] = None  
  7. }  
  8. implicit val localDateFormatter = new Formatter[LocalDate] {  
  9.  def bind(key: String, data: Map[String, String]) =  
  10.   data.get(key) map { value =>  
  11.   Try {  
  12.    Right(LocalDate.parse(value))  
  13.   } getOrElse Left(Seq(FormError(key, "error.date", Nil)))  
  14.  } getOrElse Left(Seq(FormError(key, "error.required", Nil)))  
  15.  def unbind(key: String, ld: LocalDate) = Map(key -> ld.toString)  
  16.  override val format = Some(("date.format", Nil))  
  17. }  

 

并向messages中添加:
date.format=Date (YYYY-MM-DD)
error.date=Date formatted as YYYY-MM-DD expected
再用Forms.of讲其转化为Mapping[T]:
val localDateMapping = Forms.of(localDateFormatter)得到Mapping[LocalDate] 因为of的参数是implict上面也写了localDateFormatter是implicit的 
也可以写成:
val localDateMapping = Forms.of[LocalDate]
最后使用就可以获得Form了:
val localDateForm = Form(single(
 "introductionDate" -> localDateMapping
)) 
single和tuple是一样的 只有一个参数的话可以用他


 

文件上传:

如果是单一的文件上传的话:
手工写form的格式:

Html代码   收藏代码
  1. <form action="@routes.FileUpload.upload" method="post" enctype="multipart/form-data">  
  2.  <input type="file" name="image">  
  3.  <input type="submit">  
  4. </form>  

 
Action的处理:

Scala代码   收藏代码
  1. def upload() = Action(parse.multipartFormData) { request =>  
  2.  request.body.file("image").map { file =>  
  3.   file.ref.moveTo(new File("/tmp/image"))  
  4.   Ok("Retrieved file %s" format file.filename)  
  5.  }.getOrElse(BadRequest("File missing!"))  
  6. }  

 

 

 

和form一起的操作:

Scala代码   收藏代码
  1. def upload() = Action(parse.multipartFormData) { implicit request =>  
  2.  val form = Form(tuple(  
  3.   "description" -> text,  
  4.   //因为FilePart参数得不到 自己手工写到ignored里  
  5.   "image" -> ignored(request.body.file("image")).verifying("File missing", _.isDefined))   
  6.   )  
  7.     
  8.  form.bindFromRequest.fold(  
  9.  formWithErrors => {  
  10.   Ok(views.html.fileupload.uploadform(formWithErrors))  
  11.  },value => Ok)  
  12. }  

 
于是这个Form就变成了:
Form[(String,Option[play.api.mvc.MultipartFormData.FilePart[play.api.libs.Files.TemporaryFile]])]
用helper的话:

Html代码   收藏代码
  1. @(form:Form[_])  
  2. @helper.form(action = routes.FileUpload.upload,'enctype -> "multipart/form-data") {  
  3.  @helper.inputText(form("description"))  
  4.  @helper.inputFile(form("image"))  
  5. }  

 
不过这样做的话就不能用upload里的form来传递给空白页了因为在实现里用到了request

Scala代码   收藏代码
  1. def showUploadForm() = Action {  
  2.  val dummyForm = Form(ignored("dummy"))  
  3.  Ok(views.html.fileupload.uploadform(dummyForm))  
  4. }  

可以用一个什么都不做的表格

 

form的内容是比较多的 以上的笔记可能有做得不是很容易理解的地方 需要自己多尝试一下 当初学form的时候也用了比较长的时间 



本文来自:http://fair-jm.iteye.com/  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值