I am new to play framework having some dificulties in accesing check box in controller. My view is:-
#(img:Form[Image])
#helper.form(action = routes.Application.abc) {
<li><input name="item[0]" value="pt" type=checkBox></li>
<li><input name="item[1]" value="sumit" type=checkBox></li>
<p>
<button type=submit id=imgButton>submit</button>
</p>
}
My conntroller is:-
def abc = Action{
implicit request =>
val values =ImageForm.bindFromRequest.get
println("mapinggg"+values)
Ok("hi")
}
My case class to handle checkbox is:-
case class Image (desc:List[String])
and form is
val ImageForm =Form(
mapping(
"desc" -> list(text)
)(Image.apply)(Image.unapply)
)
But it returns nill when I click on submit by selecting checkbox?
It gives output as Image(List()) but I want list of selected checkboxes
The names of your inputs ("item" - without the indices) needs to match the key of your list mapping (here given as "desc") for the binding to succeed. It should work if you change the ImageForm mapping to:
val ImageForm =Form(
mapping(
"item" -> list(text)
)(Image.apply)(Image.unapply)
)
Note that the actual field name in your case class - "desc" - should not matter here.
Related
I am experimenting with play/scala. I have following two case classes and I want to map data from form into this model
case class User (
name:String,
age:Int,
female:Boolean,
address:Address
)
case class Address (
fullStreet:String,
county:String,
country:String
)
In controller class, I have following mapping function and action defined
val userForm = Form((mapping("name"->text,
"age"->number,
"female"->boolean,
"address"->mapping("fullStreet"->text,
"county"->text,
"country"->text)(Address.apply)(Address.unapply)
)(User.apply)(User.unapply)))
def post = Action { implicit request =>
val u:Form[User] = userForm.bindFromRequest
Ok(views.html.dataIndex(u))
}
I am facing the following issue: To make the complete code work, I have to create a form which contains all the fields required in mapping as follows:
<h1>Feed User Data</h1>
#helper.form(action=routes.Data.post){
#helper.inputText(userForm("name"))
#helper.inputText(userForm("age"))
#helper.checkbox(userForm("female"))
<fieldset>
#helper.inputText(userForm("address.fullStreet"),'_label -> "Full Street")
#helper.inputText(userForm("address.county"),'_label -> "County")
#helper.select(userForm("address.country"),Seq(""->"---",
"United Kingdom"->"UK",
"France"->"FR") )
</fieldset>
<input type="submit" name="send" value="submit"/>
}
If I create a form with say only input field for name, then bindFromRequest returns None instead of mapping only name field. Is there a way in which the form can contain less fields than required in mapping. I am not talking about fields in form with empty/optional values. I do not want to put the fields in the form at all.
I usually create a case class that represents the form data (probably not all the info from the domain class), and in the controller/service I create the domain entity using my own rules (for instance, a default value for a field not represented on the form)
I have a record class like this:
class Address extends Record[Address] {
def meta = Address
object countryCode extends OptionalStringField(this, None) {
override def name = "Country"
var c = "" // this isn't doing anything but I set it up just to build the simple SHtml.select
override def toForm = Full(SHtml.select(List(("usa", "usa"),("ca", "ca")), Empty, c = _ ))
}
...
}
object Address extends Address with MetaRecord[Address] { }
and then this form is displayed like this:
object FormPage extends CssBoundLiftScreen {
def formName = "MyForm"
val record = Address.createRecord
field(record.countryCode, FieldBinding("addressCountryCode")
}
in a template like this:
<div class="form">
<div class="lift:FormPage">
<div class="fields">
<fieldset>
<div id="MyForm_addressCountryCode_field"></div>
</fieldset>
</div>
</div>
</div>
Is this the right way to do inputs other than a simple text field using Record/CssBoundLiftScreen? It doesn't seem like this select would update or create a record properly. How would I have the select show the value of the record field?
If you look at the scaladaoc for OptionalStringField, there are two methods that are provided through the superclass SettableValueHolder and that provide access to the underlying value: get and set
def set (in: Option[MyType]) : Option[MyType]
Set the value of the field to the given value. Note: Because setting a field can fail (return non-Full), this method will return defaultValueBox if the field could not be set.
get : Option[MyType]
get the value
I suspect something like this should work for you:
override def toForm = Full(SHtml.select(List(("usa", "usa"),("ca", "ca")), get, v => set(Some(v)) ))
I am using Play 2.1.2 and I have a Form with the following mapping:
Form(
mapping(
"id" -> ignored(NotAssigned: Pk[Long]),
"name" -> nonEmptyText,
"stock" -> number(min = 0),
"initialAmount" -> number(min = 0),
"distUnitId" -> longNumber,
"categoryId" -> longNumber
)
(BarItem.apply)
(BarItem.unapply)
)
In the view, I want to use a form helper to edit only part of the values. In particular, the "initialAmount" value is meant to be only set once - when creating an item - and not be allowed to change on edit. So I just do not want to display it in the form and "keep" its previous value after form submission.
Currently the interesting part of the edit view looks like this:
#form(routes.Application.update(id), 'class -> "form-inline") {
<fieldset>
#inputText(barItemEditForm("name"), '_label -> "Produktbezeichnung")
#inputText(barItemEditForm("stock"), '_label -> "Lagermenge")
#select(
barItemEditForm("distUnitId"),
distUnits,
'_label -> "Einheit"
)
#select(
barItemEditForm("categoryId"),
categories,
'_label -> "Kategorie"
)
When navigating to the edit view, I fill the form with the fill() method of the Form class:
BarItem.findById(id).map {
item =>
Ok(html.edit(id, barItemEditForm.fill(item), DistUnit.selectOptions, Category.selectOptions))
}.getOrElse(NotFound)
In the action, that handles the form submission I bind the Form from request like so:
...
implicit request =>
barItemEditForm.bindFromRequest.fold(
formWithErrors => BadRequest(html.edit(id, formWithErrors, DistUnit.selectOptions, Category.selectOptions)),
item => {
...updateStuff...
}
)
...
So the problem is now, that as I do not have an input field for "initialAmount" in the view, I get an error when binding from request, saying it has no value.
Is it somehow possible to only apply part of the values from request and keep this one value from the call to fill() before?
Or can anyone suggest a proper way to handle this kind of "partial editing"?
I'm really looking forward to any suggestions!
Since you want to keep the value, that probably means a hidden input when you rerender the form. If the previous value comes from elsewhere, e.g. the database, you could define another form with an ignored mapping for that field.
I'm looking for a solution to accomplish the same thing as in this similar question:
HTML forms with java Play Framework 2
But in Scala. Is there a way to do this? I just have one text field and a submit button. I want to get the value from the text field when pressing my button and pass this value to backend code.
object MyController extends Controller {
val submissionForm = Form(
single("myvalue" -> text)
)
def myaction = TODO //as like #mbarlocker told before
}
On such a simple case of a single input, you don't have to use mapping in form definition and you don't have to use any template helper at the input. Template helpers are useful but in this case you get freedom over the layout, without writing a custom field constructor. For example, if you need to place the the submit button next to the input field, just write something like this:
#form(routes.Application.myaction, 'class -> "form-inline") {
<input type="text" id="myvalue" name="myvalue" value="#submissionForm.data.get("myvalue")">
<input type="submit" class="btn" value="Submit :)">
}
Basically, set up the view & form the same way as in HTML forms with java Play Framework 2, and then put this in your controller.
object MyController extends Controller {
case class Submission(value: String)
val submissionForm = Form(
mapping(
"value" -> text
)(Submission.apply)(Submission.unapply)
)
def myaction = Action { implicit request =>
submissionForm.bindFromRequest().fold(
formWithErrors => {
// do something with the bad form, like reshow the view
Ok("got a bad form")
},
submission => {
// do something with the submitted form
Ok("got " + submission.value)
}
)
}
}
Play 2.1 Forms Documentation
I've got this form mapping:
val myElement = Form(
mapping(
"title" -> nonEmptyText,
"schedule" ->
tuple("startSchedule" -> jodaDate("dd/MM/yyyy HH:mm"),
"endSchedule" -> jodaDate("dd/MM/yyyy HH:mm"))
.verifying(MyValidator().checkForEndScheduleConsistency("error.schedule")),
)(MyElement.apply)(MyElement.unapply)
)
MyElement class:
case class MyElement(title: String, schedule: (Datetime, Datetime))
MyValidator class:
def checkForEndScheduleConsistency(errorMsg: String) =
Constraint[(DateTime, DateTime)]("constraint.schedule", errorMsg) {
schedule =>
MyDomainValidator().checkForEndScheduleConsistency(schedule._1, schedule._2, Messages(errorMsg)) match {
case Success(s) => Valid
case Failure(f) => Invalid(ValidationError("custom error string from `f`"))
}
}
Requirement: An error message must be associated to the field schedule.endSchedule(tuple's element) if the schedule is inconsistent according to MyValidator object.
However, in order to have both required elements (startSchedule and endSchedule) available for checkForEndScheduleConsistency method, I can't apply a verifying method directly on the nested tuple's element named endSchedule. Instead, I have to apply one on the whole tuple in order to include startSchedule variable, as shown in the code snippet.
The drawback is that the error is not mapped to endSchedule but to schedule (that doesn't represent anything in my HTML form), and so nothing is displayed to screen when an inconsistent schedule appears.
Therefore, I have to use this "workaround" to achieve my requirement using Form's withError method:
def create = Action {
implicit request =>
myForm.bindFromRequest.fold(
myFormWithErrors => {
myFormWithErrors.error("schedule") match { //check for the presence of potential schedule error
case Some(e) => {
BadRequest(views.html.create_element("Create an element", myFormWithErrors.withError("schedule.endSchedule", Messages("error.schedule"))))
}
case _ => BadRequest(views.html.create_element("Create an element", myFormWithErrors))
}
},
myForm => {
treatSubmittedMyForm(myForm)
}
)
}
=> Very ugly and anti-DRY.
Is there a way to apply verifying on the tuple and despite of that, apply the error message to a nested tuple's element? In my case, on endSchedule.
Probably the best solution is to replace the default helpers provided by Play when rendering the field by one of your own making, as per documentation:
#(elements: helper.FieldElements)
<div class="#if(elements.hasErrors) {error}">
<label for="#elements.id">#elements.label</label>
<div class="input">
#elements.input
<span class="errors">#elements.errors.mkString(", ")</span>
<span class="help">#elements.infos.mkString(", ")</span>
</div>
</div>
That way you can manually replace the error reference to the right element. Not extremely nice but you should be able to create a reusable tag from it.
The best solution is to precise the global (to schedule) "error" key into the more specific generated input directly, here the schedule.endSchedule input:
#inputText(hobbyForm("schedule.endSchedule"), 'id -> "schedule.endSchedule", '_error -> hobbyForm.error("schedule")
Notice the part: '_error -> hobbyForm.error("schedule")