rendering and binding form with checkbox data - scala

How can we create checkboxes and bind them with our form in play2.0 using scala.
If I have
val placeForm = Form(
mapping(
"id" -> ignored(NotAssigned: Pk[Long]),
"url_key" -> nonEmptyText,
"title" -> optional(text),
"page_id" -> optional(longNumber)
)(models.Place.apply)(models.Place.unapply)
)
and I have created form like this.
#form(routes.Page.save) {
#form(routes.Page.save) {
<fieldset>
#inputText(pageForm("title"), '_label -> "Title")
#inputText(pageForm("template"), '_label -> "Template") <label>Options:</label>
<div class="input">
<label>note <input type="checkbox" name="options[]" value="0">
</label> <label>About US <input type="checkbox" name="options[]"
value="0">
</label> <label>Facebook <input type="checkbox" name="options[]"
value="0">
</label> <label>Twitter <input type="checkbox" name="options[]"
value="0">
</label> <label>Hotmail <input type="checkbox" name="options[]"
value="0">
</label> <label>Something <input type="checkbox" name="options[]"
value="0">
</label>
</div>
</fieldset>
Now I want dont want simple html to create these checkboxes and bind these checkbox values into form
Can anyone help me with this

The structure of your val placeForm must match the form that you render in your template.
For example :
val placeForm = Form(
mapping(
"id" -> ignored(NotAssigned: Pk[Long]),
"title" -> optional(text),
"template" -> optional(text),
"checkbox1" -> text
"checkbox2" -> text
) // ... here construction and deconstruction functions
)
Your template can lookes like :
#form(routes.Page.save) {
<fieldset>
#inputText(pageForm("title"), '_label -> "Title")
#inputText(pageForm("template"), '_label -> "Template")
<label>Options:</label>
<div class="input">
<label> 1 <input type="checkbox" name="checkbox1" value="1"> </label>
<label> 2 <input type="checkbox" name="checkbox2" value="2"> </label>
</div>
</fieldset>
}
Now it's important to understand for wich purposes are these checkboxes. If you want to bind there values to your case class Place and your form structure match completely your case class, you can use apply and unaplly method, if no ... you must utilise your custom functions...
((title, template, checkbox1, checkbox2)=> Place(title, template, checkbox1, checkbox2)) //construct function
((place : Place) => Some((place.title, place.template, place.property_that_correspond_to_checkbox1_value,place.property_that_correspond_to_checkbox2_value)) // deconstruct function
Or you can use tuple instead of mapping for a form construction and then get your values simply as tuple values

Related

Displaying a list of checkboxes in my form

I want to display many checkboxes inline like:
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckboxA" value="optionA"> A
</label>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckboxB" value="optionB"> B
</label>
<label class="checkbox-inline">
<input type="checkbox" id="inlineCheckboxC" value="optionC"> C
</label>
So I have my form like:
val form: Form[SearchForm] = Form(
mapping(
"letters" -> list(text)
)
)(SearchForm.apply)(SearchForm.unapply _)
Can I somehow pre-populate my form with the data or do I have to pass another variable with my view that has this 'letters' data?
val letters = List[String]("A", "B", "C", ...)
If I can't pass this letters val down with my view, then I guess I just pass another variable with my model and just iterate over it?
Have you looked at the helper inputCheckboxGroup ?
That will pre-populate the form elements from your model but you'll still have to provide the checkbox group with the set of possible values.
For example:
#views.html.helper.inputCheckboxGroup(
form("letters"),
options = Seq("A" -> "alpha", "B" -> "beta", "C" -> "gamma"),
'_label -> "My cool checkbox"
)
and the form filled with:
val form: Form[SimpleForm] = Form(mapping(
"letters" -> list(text)
)(SimpleForm.apply)(SimpleForm.unapply))
SimpleForm.form.fill(SimpleForm(List("A", "B")))
Would render a checkbox group like this:
[x] alpha [x] beta [ ] gamma

How to define custom scala input helper for checkbox

I am trying to build an input helper for Play Framework in Scala.
I would like to have my inputs of type radio and checkbox to be printed differently than the standard text or password input types ?
Here is my custom helper:
#(elements: helper.FieldElements)
<div class="form-group">
<label for="#elements.id" class="col-lg-2 control-label">#elements.label</label>
<div class="col-lg-10">
<input type="text" class="form-control" id="#elements.id" />
</div>
</div>
But this prints an text input instead of checkbox input. Which is strange behaviour.
I've read the documentation, but couldn't find anything about it.
Here is how I import this helper to view:
#implicitFieldConstructor = #{ FieldConstructor(generic.views.html.FormHelpers.twitterBootstrapInputSupraClub.render) }
#checkboxFieldConstructor = #{ FieldConstructor(generic.views.html.FormHelpers.twitterBootstrapInputSupraClubCheckbox.render) }
And this is how I call helpers to build input (generates inputs) in view:
#inputText(
accountRegistrationForm("email"),
'_label -> "email"
)
#inputPassword(
accountRegistrationForm("password"),
'_label -> password
)
#inputRadioGroup(
accountRegistrationForm("regulationAcceptance"),
options = Seq("true"->"Yes"),
'_label -> "I agree with regulation",
'type -> "radio"
)(handler = checkboxFieldConstructor, implicitly[Lang])
I might be missing something here but as far as I can see, you seem to me missing the right input type.
In your helper, try changing <input type="text"... to <input type="radio"...
You can pass the input type dynamically, too. e.g.
#(elements: helper.FieldElements, inputType: String)
<div class="form-group">
<label for="#elements.id" class="col-lg-2 control-label">#elements.label</label>
<div class="col-lg-10">
<input type="#inputType" class="form-control" id="#elements.id" />
</div>
</div>
EDIT:
I have something similar to this for radio buttons:
given that my userDetailForm contains canLogOn:
"company" -> nonEmptyText,
"canLogon" -> boolean,
"canTrade" -> boolean,
I created a function in views: radioSet(fieldName: String)
#radioSet(fieldName: String) = {
<label for="#fieldName">Can Logon</label>
<input name=#fieldName id=#fieldName type="radio" value = "true"
#if(userDetailForm(fieldName).value.getOrElse("false").equals("true"))
{checked}>
}
Then I call it when I need it:
#radioSet("canLogon")
And I get: http://imgur.com/RG60wxV (sorry I cant post images yet)

NoSuchElementException: None.get in play framework for scala

I need to build update method, but when i test show the error NoSuchElementException: None.get
UserController
object UserController extends Controller {
def update(id:Long) = DBAction { implicit rs =>
var user = simpleUserForm.bindFromRequest.get
user.id = Users.toOption(id)
Users.update(user)
Redirect(routes.UserController.list)
}
val simpleUserForm :Form[User] = Form {
mapping(
"firstName" -> nonEmptyText,
"lastName" -> nonEmptyText,
"email" -> email,
"birthDate" -> nonEmptyText,
"phone" -> nonEmptyText,
"username" -> text,
"password" -> nonEmptyText
)(UserForm.fromSimpleForm)(UserForm.toSimpleForm)
}
}
edit.scala.html
#import models.auth.Users
#(title: String, user:models.auth.User)
#main(title){
<form method="post" action="#controllers.auth.routes.UserController.update(Users.toLong(user.id))">
<input type="text" placeholder="First Name" name="firstName" value="#user.firstName"/><br/>
<input type="text" placeholder="Last Name" name="lastName" value="#user.lastName"/><br/>
<input type="email" placeholder="Email" name="email" value="#user.email" /><br/>
<input type="text" placeholder="Phone" name="phone" value="#user.phone" /><br/>
<input type="text" placeholder="Birthdate(dd/MM/yyyy)" name="birthDate" value="#user.birthDate" /><br/>
<input type="text" placeholder="Username" name="username" value="#user.username" /><br/>
<input type="submit" value="Update User" />
</form>
}
routes
POST /user/:id/ controllers.auth.UserController.update(id:Long)
I already done for create, read and delete, but for update i found error in line
var user = simpleUserForm.bindFromRequest.get
the error is NoSuchElementException: None.get
The Play page on Scala Forms is helpful here. That approach would be to send the populated form to the view as a parameter, then on submit use fold, which gives you options to deal with the error case as well as the "happy" case. Something like the following (adapted from the above page):
simpleUserForm.bindFromRequest.fold(
formWithErrors => {
// binding failure, you retrieve the form containing errors:
// in your form, test .hasErrors
BadRequest(views.html.user.edit(formWithErrors))
},
userData => {
/* binding success, you get the value. */
// .. do the update
...
//-- and return to list or home or...
Redirect(routes.Application.home(id))
}
)
If you don't want to use the form, then to back to your actual question, would .getOrElse not work?
did you import
import play.api.libs.concurrent.Execution.Implicits._

Play framework 2 form fields have hasError but how to check a field is valid

I want to use Bootstrap 3 validation states like
<div class="form-group has-success">
<label class="control-label" for="inputSuccess1">Input with success</label>
<input type="text" class="form-control" id="inputSuccess1">
</div>
<div class="form-group has-error">
<label class="control-label" for="inputError1">Input with error</label>
<input type="text" class="form-control" id="inputError1">
</div>
how to check the status success? Before first submiting the form field has no error, but this does not mean that the field is correct.
looking a little deeper views.html.helper.FieldElements and play.api.data.Field, i found solution (using this in helper handler)
#(elements: helper.FieldElements)
#state = {
#if(elements.hasErrors) {
has-error
} else {
#if(elements.field.value.isDefined) {
has-success
}
}
}
field.value is None if play.api.data.Form is empty (without filling or binding).
val registerForm = Form(
tuple(
"firstName" -> nonEmptyText,
"lastName" -> nonEmptyText
)
)
Ok(views.html.register(registerForm))

Yesod: Custom divs and forms

How to make Yesod generate complicated forms like this:
<form class="form-horizontal">
<div class="form-group">
<label for="text1" class="control-label col-lg-4">
Normal Input Field
</label>
<div class="col-lg-8">
<input type="text" id="text1" placeholder="Email" class="form-control">
</div>
</div>
<!-- /.form-group -->
<div class="form-group">
<label for="pass1" class="control-label col-lg-4">
Password Field
</label>
<div class="col-lg-8">
<input class="form-control" type="password" id="pass1" data-original-title="Please use your secure password" data-placement="top" />
</div>
</div>
</form>
I know that Yesod can create a generic form but is it possible to do the following things:
Wrap a div around a textbox
Wrap the label and input textbox also in another div.
Does Yesod allow to do these stuff for generating highly customized forms ?
Yesod provides the ability of defining custom fields which is very well explained in their documentation.
Also, I define two custom fields for the above problem:
textBoxField :: Text -> Field Handler Text
textBoxField label = Field
{ fieldParse = \rawVals _ ->
case rawVals of
[a] -> return $ Right $ Just a
[] -> return $ Right Nothing
, fieldView = \idAttr nameAttr otherAttrs eResult isReq ->
[whamlet|
<div class="form-group">
<label for=#{idAttr} class="control-label col-lg-4">#{label}
<div class="col-lg-8">
<input id=#{idAttr} name=#{nameAttr} *{otherAttrs}
type="text" class="form-control">
|]
, fieldEnctype = UrlEncoded
}
cPasswordField :: Text -> Field Handler Text
cPasswordField label = Field
{ fieldParse = \rawVals _ ->
case rawVals of
[a] -> return $ Right $ Just a
[] -> return $ Right Nothing
, fieldView = \idAttr nameAttr otherAttrs eResult isReq ->
[whamlet|
<div class="form-group">
<label for=#{idAttr} class="control-label col-lg-4">#{label}
<div class="col-lg-8">
<input id=#{idAttr} name=#{nameAttr} *{otherAttrs}
type="password" class="form-control"
data-original-title="Please use your secure password" data-placement="top">
|]
, fieldEnctype = UrlEncoded
}
These functions can be later utilized to build up the actual form. The entire working code is here.
Have you looked into runInputPost and ireq? Else look at the form chapter in the yesod book.
But, to give you an example, you can create exactly the form you want, and then just use something like this in the POST request,
-- Handling the blog article form
postAdminNewArticleR :: Handler Html
postAdminNewArticleR = do
title <- runInputPost $ ireq textField "form-title-field"
htmlContent <- runInputPost $ ireq htmlField "form-htmlcontent-field"
-- insert into the database or something
For the form handler itself, you'd probably do,
-- The form page for posting a new blog article
getAdminNewArticleR :: Handler Html
getAdminNewArticleR = do
formroute <- return $ AdminNewArticleR
defaultLayout $ do
-- ...
and lastly, the hamlet for the form page would look like,
<form method=post action=#{formroute}>
<input name="form-title-field">
<textarea name="form-htmlcontent-field">
This gives you 100% control of the forms.