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)
Related
I'd like to know how to improve my own kind of template's helper. For instance, I made an autocomplete.scala.html that receives parameters in order to be dynamic, something like:
#autocomplete("elementLabel","data-url-where-its-going-to-get-JSON-data","anyother","etc","foo")
Then I can use autocomplete component in any page I want to.
But I'm wondering how to make it easier to use, for instance, Play's inputText helper has the option you can add parameters using " ' " + parametername and then -> (probably lambda?) so, how could i implement it, so, I could, for instance make something like:
#autocomplete("data-url",'someattribute->"value", '_anotherOneWithUnderscoreWhyBtw->"whyunderscore")
autocomplete.scala.html
#**
* Componente para pesquisa textual e sele��o de registro de relacionamento 1 para N
*
* Example:
*
* #autocomplete("example.nested.id", "Unidade", "/sistema/buscarExemplo", myForm.get().getUnidade.getId.toString, myForm.get().getUnidade.getLabel.toString)
*#
#(fieldId: String, fieldTitle: String, dataUrl: String, initIdValue: String, initTitleValue: String)
<div class="form-group">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<label for="#fieldId" class="control-label">#fieldTitle</label>
</div>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<span class="input-icon input-icon-right" style="width:100%">
<input type="text" class="autocomplete-relation"
name="#fieldId"
data-url="#dataUrl"
data-id-status="#fieldTitle"
data-init-id-value="#initIdValue"
data-init-nome-value="#initTitleValue"
style="width:100%"
/>
<i id="response_#fieldTitle" class="icon-search blue"></i>
</span>
</div>
</div>
As soon as new requirements appear i must add one more parameter and then modify it at all pages i call it. I wanted to use that component like that original checkbox, from play, for instance:
#checkbox(myForm("myField"),'_label ->"MY_LABEL", 'class->"MYCLASS")
OR
#checkbox(myForm("myField"),'class ->"MYCLASS",'_label->"MY_LABEL")
or even
#checkbox(myForm("myField"),'class ->"MYCLASS",'_label->"MY_LABEL",'anotheattribute->"VALUE")
and so on. How could I do it so I wouldn't have to fill all of them and the order wouldn't matter?
You could use repeated (String, String) tuples as the last parameter:
#(fieldId: String, fieldTitle: String, data: (String, String) *)
<div class="form-group">
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<label for="#fieldId" class="control-label">#fieldTitle</label>
</div>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
<span class="input-icon input-icon-right" style="width:100%">
<input type="text" class="autocomplete-relation"
name="#fieldId"
data-id-status="#fieldTitle"
#data.map{ case (key, value) =>
#{key}="#{value}"
}
style="width:100%"
/>
<i id="response_#fieldTitle" class="icon-search blue"></i>
</span>
</div>
</div>
And you'd call it the way you're wanting:
#autocomplete("someId", "someTitle", "data-url" -> "google.com", "data-attr" -> "someValue")
You could also use a Map[String, String].
#(fieldId: String, fieldTitle: String, data: Map[String, String])
The rest of the template would remain the same, but you'd pass it something like this:
Map[String, String](
"data-url" -> "google.com",
"data-field-something" -> "value"
)
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))
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.
I'm quite new to play and scala. I'm working on form and validations. But I couldn't figure out to get all errors from multiple verification on form.
My form tuple looks like;
val companyMapping = Forms.tuple(
"name" -> nonEmptyText,
"email" -> email,
"password" -> nonEmptyText(8),
"re-password" ->nonEmptyText(8)).verifying(
// Add an additional constraint: both passwords must match
"Passwords don't match", data => {
data._3 == data._4 }
).verifying(
// Second constraint
"Test error", data => {
false }
)
In the view I print global errors and errors, it looks like;
#println(companyForm.globalError)
#println(companyForm.errors)
and output;
Some(FormError(,Passwords don't match,WrappedArray()))
List(FormError(,Passwords don't match,WrappedArray()), FormError(,Test error,WrappedArray()))
At this stage I have absolutely no idea about how to print both of the errors. I'm showing errors separately for the each input and show global errors at the end.
But if passwords match I can see test constraint in the global errors. Other than it only shows password match constraint.
Here is the view part;
#helper.form(action = routes.Login.register) {
<div class="row">
<span class="label">Name</span>
<input type="text" name="name" placeholder="Company Name" value="#companyForm("name").value" >
#if(!companyForm.errors("name").isEmpty){
<span class="error">#Messages(companyForm.errors("name")(0).message,"Company name")</span>
}
</div>
<div class="row">
<span class="label">Email</span>
<input type="text" name="email" placeholder="Email" value="#companyForm("email").value" >
#if(!companyForm.errors("email").isEmpty){
<span class="error">#Messages(companyForm.errors("email")(0).message,companyForm.errors("email")(0).key)</span>
}
</div>
<div class="row">
<span class="label">Password</span>
<input type="password" name="password" placeholder="Password" value="#companyForm("password").value" >
#if(!companyForm.errors("password").isEmpty){
<span class="error">#Messages(companyForm.errors("password")(0).message,8)</span>
}
</div>
<div class="row">
<span class="label">Re-type Password</span>
<input type="password" name="re-password" placeholder="Re-type your password" value="#companyForm("re-password").value" >
#if(!companyForm.errors("re-password").isEmpty){
<span class="error">#Messages(companyForm.errors("re-password")(0).message,8)</span>
}
</div>
#println(companyForm.globalError)
#println(companyForm.errors)
<div class="row">
<span class="label"><button type="submit">Save</button></span>
#companyForm.globalError.map { error =>
<span class="error">#error.message</span>
}
</div>
}
Maybe I'm just confused about those error types. So please can you explain it detailed.
In the re-password section of your template, you currently test if !companyForm.errors("re-password").isEmpty but then only show the message for companyForm.errors("re-password")(0), i.e. the first error only. Even if you have multiple errors.
You have to iterate over companyForm.errors("re-password") to print something for each error.
You can for example output a <span class="error">... for each error, using a for comprehension:
<div class="row">
<span class="label">Re-type Password</span>
<input type="password" name="re-password" placeholder="Re-type your password" value="#companyForm("re-password").value" >
#for (error <- companyForm.errors("re-password")) {
<span class="error">#Messages(error.message,8)</span>
}
</div>
See the play doc for Scala templates for other useful syntax to use in templates.
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