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
Related
I'm working on a Scala Play 2.7.x (you may checkout the project here play-silhouette-seed googleauth branch) and I have a form defined as:
object TotpSetupForm {
val form = Form(
mapping(
"sharedKey" -> nonEmptyText,
"scratchCodes" -> seq(mapping(
"hasher" -> nonEmptyText,
"password" -> nonEmptyText,
"salt" -> optional(nonEmptyText)
)(PasswordInfo.apply)(PasswordInfo.unapply)),
"scratchCodesPlain" -> optional(seq(nonEmptyText)),
"verificationCode" -> nonEmptyText(minLength = 6, maxLength = 6)
)(Data.apply)(Data.unapply)
)
case class Data(
sharedKey: String,
scratchCodes: Seq[PasswordInfo],
scratchCodesPlain: Option[Seq[String]],
verificationCode: String = "")
}
Where PasswordInfo comes from Play-Silhouette and looks like:
case class PasswordInfo(
hasher: String,
password: String,
salt: Option[String] = None
) extends AuthInfo
In my controller I populate the form and pass it as parameter to my view template as follows. Note that I have debugged it and totpInfo.scratchCodes has 5 values and the form is correctly populated:
val formData = TotpSetupForm.form.fill(TotpSetupForm.Data(totpInfo.sharedKey, totpInfo.scratchCodes, totpInfo.scratchCodesPlain))
Ok(views.html.someView(formData, ...)
I render the view as follows, please note that I did read the Scala Forms Repeated Values documentation note :)
#helper.form(action = controllers.routes.TotpController.submit()) {
#helper.CSRF.formField
#b3.text(totpForm("verificationCode"), '_hiddenLabel -> messages("verificationCode"), 'placeholder -> messages("verificationCode"), 'autocomplete -> "off", 'class -> "form-control input-lg")
#b3.hidden(totpForm("sharedKey"))
#helper.repeatWithIndex(totpForm("scratchCodes"), min = 1) { (scratchCodeField, index) =>
#b3.hidden(scratchCodeField, '_label -> ("scratchCode #" + index))
}
<div class="form-group">
<div>
<button id="submit" type="submit" value="submit" class="btn btn-lg btn-primary btn-block">#messages("verify")</button>
</div>
</div>
}
even though the form's scratchCodes sequence is correctly populated, each of the sequence values render as empty:
<input type="hidden" name="scratchCodes[0]" value="" >
<input type="hidden" name="scratchCodes[1]" value="" >
<input type="hidden" name="scratchCodes[2]" value="" >
<input type="hidden" name="scratchCodes[3]" value="" >
<input type="hidden" name="scratchCodes[4]" value="" >
The number of fields in the sequence is correct though.
I have also tried using the #helper.repeat alternative and even using the #helper.input instead of #b3.hidden just to be sure and the result is always the same ... I get empty valued PasswordInfo tuples rendered.
How can I fix this?
OK found the culprit: repeated + nested values require accessing each attribute separately like this:
#helper.repeat(totpForm("scratchCodes"), min = 1) { scratchCodeField =>
#b3.hidden(scratchCodeField("hasher"))
#b3.hidden(scratchCodeField("password"))
#b3.hidden(scratchCodeField("salt"))
}
then works fine and the post request populates the sequence of PasswordInfo UDTs correctly.
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)
I have read several times the documentation but I still have problems with my nested form in Play! Scala 2.2 (detailed further).
Here is my form :
<form method="post" action="/admin/test2">
first name : <input type="text" name="firstname"> <br>
info 0 : <input type="text" name="label[0]"> <br>
info 1 : <input type="text" name="label[1]"> <br>
<input type="submit" value="test nested form" />
</form>
And the case classes corresponding :
case class Contact(firstname: String,
informations: Seq[ContactInformation])
case class ContactInformation(label: String)
val contactForm: Form[Contact] = Form(
mapping(
"firstname" -> nonEmptyText,
"informations" -> seq(
mapping(
"label" -> nonEmptyText
)(ContactInformation.apply)(ContactInformation.unapply)
)
)(Contact.apply)(Contact.unapply)
)
def saveContact = Action { implicit request =>
contactForm.bindFromRequest.fold(
formWithErrors => Ok("error"),
contact => {
println(contact)
Ok("Done")
}
)
}
I don't get any errors, but the contact that I get from the form (printed with println(contact)) has an empty informations field, i.e. it looks like this : Contact(h,List())
The error comes probably from the html part since I have followed to the letter the documentation from this page : play! scala forms documentation
but I can’t figure it out.
The field names of the inputs should use the full path in the Form. label appears within the informations Mapping, and informations is the sequence, not the label, so you should use informations[0].label instead of label[0].
Your view should look like this:
first name : <input type="text" name="firstname"> <br>
info 0 : <input type="text" name="informations[0].label"> <br>
info 1 : <input type="text" name="informations[1].label"> <br>
I have a form which is like a quiz/questionnaire type design to it.
So say the page is a quiz, it will display a dynamic number of questions on the page, and each question will have a list of checkbox options (the user can select 1+ checkboxes).
How can I represent this type of form in play?
case class Quiz(id: Int, name: String)
case case Question(id: Int, quizId: Int, title: String)
case class QuestionOption(id: Int, questionId: Int, name:String)
So you have a quiz, that has many questions. And each question has multiple QuestionOptions.
So the form would be something like:
case class QuizForm(quiz: Quiz, questions: List[Question], options: List[QuestionOption])
For each question, you can select 1 or more QuestionOption.
I would nest the Questions within Quiz, and QuestionOptions within Question. That could make this a little more compact in the end.
case class Quiz(id: Int, name: String, questions: List[Question])
case class Question(id: Int, quizId: Int, title: String, options: List[QuestionOption])
case class QuestionOption(id: Int, questionId: Int, name: String)
A possible implementation of the Form would use lists of mapping:
val quizForm: Form[Quiz] = Form {
mapping(
"id" -> number,
"name" -> nonEmptyText,
"questions" -> list(mapping(
"id" -> number,
"quizId" -> number,
"title" -> nonEmptyText,
"options" -> list(mapping(
"id" -> number,
"questionId" -> number,
"name" -> nonEmptyText
)(QuestionOption.apply)(QuestionOption.unapply))
)(Question.apply)(Question.unapply))
)(Quiz.apply)(Quiz.unapply)
}
The very verbose part is the HTML form, which needs to contain all of these fields. Here is a sample of data a form would send (one question, multiple answers).
val data = Map(
"id" -> "1",
"name" -> "My Quiz",
"questions[0].id" -> "1",
"questions[0].quizId" -> "1",
"questions[0].title" -> "What?",
"questions[0].options[0].id" -> "1",
"questions[0].options[0].questionId" -> "1",
"questions[0].options[0].name" -> "red",
"questions[0].options[1].id" -> "2",
"questions[0].options[1].questionId" -> "1",
"questions[0].options[1].name" -> "green",
"questions[0].options[2].id" -> "4",
"questions[0].options[2].questionId" -> "1",
"questions[0].options[2].name" -> "blue"
)
The name fields of each of the question meta data / answers will need to have unique indices that bind them together. Here's a crude example:
<input type="hidden" name="id" value="1">
<input type="hidden" name="name" value="My Quiz">
<input type="hidden" name="questions[0].id" value="1">
<input type="hidden" name="questions[0].quizId" value="1">
<input type="hidden" name="questions[0].title" value="What?">
<input type="hidden" name="questions[0].options[0].id" value="1">
<input type="hidden" name="questions[0].options[0].questionId" value="1">
<input type="checkbox" name="questions[0].options[0].name" value="red">
<input type="hidden" name="questions[0].options[1].id" value="2">
<input type="hidden" name="questions[0].options[1].questionId" value="1">
<input type="checkbox" name="questions[0].options[1].name" value="green">
<input type="hidden" name="questions[0].options[2].id" value="3">
<input type="hidden" name="questions[0].options[2].questionId" value="1">
<input type="checkbox" name="questions[0].options[2].name" value="blue">
<input type="hidden" name="questions[0].options[3].id" value="4">
<input type="hidden" name="questions[0].options[3].questionId" value="1">
<input type="checkbox" name="questions[0].options[3].name" value="orange">
We can probably make this smaller by removing some of the title/name fields and ignoring them in the Form, since they shouldn't matter for persistence. But this gets rather verbose very quickly.
It's at this point I usually abandon Forms and go with pure javascript, as JSON is much simpler to handle (and read, in my opinion).
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