How to display ad hoc constraints form validation messages? - scala

ScalaForms
In the example linked here there is this example about form validation:
// You can also define ad-hoc constraints on the fields:
val loginForm = Form(
tuple(
"email" -> nonEmptyText,
"password" -> text
) verifying("Invalid user name or password", fields => fields match {
case (e, p) => User.authenticate(e,p).isDefined
})
)
Via binding errors some constraints are displayed in my form. (Like the nonEmptyText, that gets a extra line behind the field stating This field is required. See:
loginForm.bindFromRequest.fold(
formWithErrors => // binding failure, you retrieve the form containing errors,
value => // binding success, you get the actual value
)
If I do a .toString to the formWithErrors i get this for the nonEmptyText constraint:
Form(ObjectMapping2(<function2>,<function1>,(Email adress,FieldMapping(,List(Constraint(Some(constraint.required),WrappedArray())))),(Password,FieldMapping(,List(Constraint(Some(constraint.required),WrappedArray())))),,List(Constraint(None,List()))),Map(Password -> test, Email adress -> ),List(FormError(Email adress,error.required,WrappedArray())),None)
The latter part is a FormError List: List(FormError(Email adress,error.required,WrappedArray())),None) which is a case class: case class FormError (key: String, message: String, args: Seq[Any]) where key is defined as: The error key (should be associated with a field using the same key)..
The FieldConstructor picks this up and makes the 'Email adress' input box go red and add the error message ('This field is required').
Displaying the ad hoc constraints?
So when the form fields are all filled the username and password are checked:
verifying("Invalid user name or password", fields => fields match {
case (e, p) => User.authenticate(e,p).isDefined
})
But i dont know how to display the 'Invalid user name or password' to the user. The .toString of the FormError List of formWithErrors is:
List(FormError(,Invalid user name or password,WrappedArray())),None)
The Key part is empty.
Question
How do i display the ad hoc error?
I even tried:
BadRequest( views.html.test( formWithErrors ) ).flashing( "error" -> "Invalid user name or password." ) },
but for some reason its not working via the Flash either :(. This #flash.get("error").getOrElse("no 'error'") gives me 'no error' each time.

Actually, a form can have errors attached to it, so then when a bind from request fails validating constraint, a new form is created based on the given one, but filled in with errors.
Such errors list is composed of FormError which refers a Form Field and overrides toString to show its embed message.
This way if you wish to show all messages at once, you can simply formWithErrors.errors.mkString("<br>") for instance (in you template or flashing it).
There are a lot of ways and some common ones are described here http://www.playframework.org/documentation/2.0.2/ScalaFormHelpers. You might define your own field constructor as well.
To conclude, my advice would be that you should use helpers amap (for instance #inputText and co) because they already contain the logic to show helpers, tips and errors when available.
Edit
I missed the hint about the flash problem... you've probably forgotten to add (implicit flash: Flash) to you template param list. (don't forget to flag the request as implicit as well in your action definition)

Related

how to make mapping function work if the incoming request has less fields than expected

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)

Optional checkbox in Scala Play - form does not validate

I just started with Play and I'm trying to create a form with an "optional checkbox". The user must agree to the general terms (don't share your login credentials, ...). The second checkbox is optional and the user can decide whether this hint should be shown in the future again when he logs in the next time:
I created some form validation code in my Scala controller:
case class AbuseStatus(abuseHintAccepted: Boolean, dismissAbuseHintInFuture: Boolean)
val abuseHintForm = Form(
mapping(
"abuseHintAccepted" -> checked("Please accept the general terms."),
"dismissHintInFuture" -> boolean
)(AbuseStatus.apply)(AbuseStatus.unapply) verifying ("you must accept the general terms", result => result match {
case abuseStatus =>
{
abuseStatus.abuseHintAccepted.booleanValue()
}
})
)
I'm using the following method to handle the POST request when the form has been sent.
def sendAbuseHintForm = Action {implicit request =>
abuseHintForm.bindFromRequest.fold(
formWithErrors =>
{
Logger.info("Form did not validate")
formWithErrors.errors.map(error => Logger.info(error.messages.mkString(",")))
Ok(views.html.abuseHint(formWithErrors))
},
abuseStatus =>
{
if(abuseStatus.dismissAbuseHintInFuture)
{
Logger.info(">>>dismissHintInFuture = true")
Ok(views.html.home()).withCookies(showAbuseHintCookie)
}
else
Ok(views.html.home())
}
)
}
The form does not validate if both checkboxes are set to true. I would like it to validate when at least the first checkbox is set to true (the second is optional). How can I achieve this and what is the difference between
"abuseHintAccepted"->checked("...")
and
"dismissHintInFuture"->boolean
They both return a Mapping[Boolean].
I have tried your example using Play 2.3.8 and it does appear to validate correctly when passing these parameters:
abuseHintAccepted:true
dismissHintInFuture:true
It would be worth making sure the form field names and values (true/false) that are posted are actually correct in all of the scenarios you describe (you haven't supplied that part of the code).
The difference between boolean and checked(msg) is that checked(msg) has validation applied ensuring the value is true - it is equivalent to boolean verifying (msg, _ == true) - (see Play framework source).
Finally, the checked() validation you have for abuseHintAccepted means that the verifying check on the whole form is not needed, but this shouldn't affect the behaviour of the form (it is just duplicate validation).

Play Framework 2 template Form None.get

Im new to Play 2 and Scala, and im getting a strange Exception in my template:
Execution exception
-------------------
[NoSuchElementException: None.get]
In /home/nic/workspaces/scala-ide/scims/app/views/persons/detailTabs/personal.scala.html at line 4.
1. #(personId: Long, personDetailTabForm: Form[dto.PersonDetailTab])(implicit formOptions: dto.PersonFormOptions)
2. #implicitFieldConstructor = #{ helper.FieldConstructor(support.bs3HorizField.f) }
3.
4. #persons.detail("personal", personDetailTabForm.get.firstName) {
The personDetailTabForm is an empty form object defined as:
val personalDetailTabForm: Form[PersonDetailTab] = Form(
mapping(
"firstName" -> text.verifying(nonEmpty),
"middleName" -> text,
"lastName" -> text.verifying(nonEmpty),
"gender" -> text,
"dateOfBirth" -> jodaDate("yyyy-MM-dd"),
"ethnicity" -> text,
"maritalStatus" -> text,
"password" -> text
)(PersonDetailTab.apply)(PersonDetailTab.unapply)
)
Any ideas as to what's wrong here?
I was under the impression a variable would have to be an Option to get a None?
Cheers
NFV
You are calling get on personDetailTabForm - Looking up it's ScalaDoc: http://www.playframework.com/documentation/2.2.x/api/scala/index.html#play.api.data.Form - it seems that .get returns the PersonDetailTab value that the form holds - IF, as the docs say, 'the submission was a success'.
You're seeing the None.get exception because most likely play.api.data.Form[T] simply uses Option[T] and get returns Some[T] when the form holds a valid value and None otherwise.
So on your line 4, in the scala template, you have something like
personDetailTabForm.get.firstName
That's a String, but you can expect a value only when the form's underlying PersonDetailTab itself has a value. I am not sure what you want to do, but you're dealing with a case where a value you want to render in a template might not be there, for whatever reason. In which case:
#personDetailTabForm.value.map{ personDetailTab =>
#persons.detail("personal", personDetailTab.firstName) // { ... whatever else
// anything else you want to render
} getOrElse { // errors in the form; personDetailTabForm cannot yield a valid personDetailTab
<h3> oops, what went wrong here? </h2>
}
It all depends on what you want to do in personal.scala.html. Form[T] is a good way
to deal with input and validation of some T thing, but if you are just displaying it,
and if you have a T (in your case PersonDetailTab) just pass that to the template as it is. If your PersonDetailTab may or may not exist, then just use Option[PersonDetailTab] instead Form[PersonDetailTab].

Only bind part of the Form mappings from request

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.

Validation errors using datamapper gem

I’m using Datamapper (1.2.0) and Sinatra (1.3.2). I have a model and a property of the model is Employee ID. This is a mandatory field so whenever this is not been entered by the user I need to throw validation error.
Datamapper intelligently identifies the name of the property as 'Employee' (cuts down id part) and displays the error as 'Employee can't be blank' and 'Employee should be an integer'.
So I tried to override these error messages. I could able to override the 'Employee can't be blank' but cannot able to override the other.
property :employee_id, Integer, :required => true, :unique => true,
:messages => {
:presence => "Employee ID cannot be blank.",
:is_unique => "Employee ID should be unique."
}
What should be the hash key I need to use to override the 'not_an_integer' error?
I think the message key you’re looking for is :is_number. Where this is documented is a bit hidden away. (I actually looked for it in the source).
Also, it seems to be if you have any :messages hash in the property options then the default messages are replaced with nil if you don’t specify a custom message for that validation.