如何为动态生成的内容编写自定义表单助手模板?
How to write a custom form helper template for dynamically generated content?
我有某种测验系统,向用户显示一个问题和几个带有单选按钮的答案选项。
但是当我使用一个通过列表填充的 inputRadioGroup 的助手时,它看起来不再漂亮了(就像 Twitter Bootstrap)。单选按钮是内联的,而它们应该在彼此的下方。实际上我想将图标更改为更漂亮的按钮。
这是目前的样子:
因此,我尝试编写自己的自定义表单助手,但一直卡壳。我发现很难理解这方面的文档:
https://www.playframework.com/documentation/2.3.x/JavaFormHelpers
首先我创建了一个名为 myFieldConstructorTemplate.scala.html
的新模板
@(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>
已将其保存到 /views 文件夹。然后尝试在我看来使用它 class quiz.scala.html:
@import helper._
@import helper.twitterBootstrap._
@(questionList: List[Question], answerList: List[Answer], answerRadioForm: Form[Answer])
@helper.form(action = routes.Application.nextQuizPage(), 'id -> "answerRadioForm"){
@helper.inputRadioGroup(
answerRadioForm("Answer"),
options = answerList.map(answer => answer.answerID.toString -> answer.answerText),
'_label -> "Answer",
'_error -> answerRadioForm("answerID").error.map(_.withMessage("select answer")))
<button type="submit" class="btn btn-default" value="Send">
Next Question
</button>
}
@implicitField = @{ FieldConstructor(myFieldConstructorTemplate.f) }
@inputText(answerRadioForm("questionID"))
如果我将它放入我的模板中,我会得到一个 not found: value implicitField
-错误。
那么我怎样才能设法将单选按钮的外观更改为在下方并看起来像 Twitter Bootstrap?
[EDIT1]: 我已将导入顺序更改为建议版本:
@(questionList: List[Question], answerList: List[Answer], answerRadioForm: Form[Answer])
@import helper._
@implicitField = @{ FieldConstructor(myFieldConstructorTemplate.f) }
@import helper.twitterBootstrap._
然后我得到这个错误:
ambiguous implicit values:
both method implicitField of type => views.html.helper.FieldConstructor
and value twitterBootstrapField in package twitterBootstrap of type
=> views.html.helper.FieldConstructor match expected type
views.html.helper.FieldConstructor
我认为这与我将答案导入单选按钮的方式有关?
[EDIT2]:
现在导入的顺序是:
@(questionList: List[Question], answerList: List[Answer], answerRadioForm: Form[Answer])
@import models.Question
@import models.Answer
@import helper._
@implicitField = @{ FieldConstructor(myFieldConstructorTemplate.f) }
至此,程序编译通过。但是单选按钮看起来还是一样的。所以我试图改变设计,但效果不佳。现在看起来所有的单选按钮都融合成了一个:
这是我的模板classmyFieldConstructorTemplate.scala.html:
@(elements: helper.FieldElements)
<div class="btn-group", data-toggle="buttons">
<label for="@elements.id">@elements.label</label>
<div class="input">
<label class="btn btn-primary">
@elements.input
<span class="errors">@elements.errors.mkString(", ")</span>
<span class="help">@elements.infos.mkString(", ")</span>
</label>
</div>
</div>
[EDIT3]: 我已经根据 , but still the radiobuttons are melted into each other. So I want to point out that I am not fixated on using the inputRadioGroup from the playframework helper 更改了我的 class,如果有另一个解决方案同样有效并且看起来几乎像 bootstrap,我很乐意使用它。似乎更改助手并不是那么容易/直观。我感谢任何形式的帮助!
将 implicitField
-定义移动到文件顶部:
@(questionList: List[Question], answerList: List[Answer], answerRadioForm: Form[Answer])
@import helper._
@implicitField = @{ FieldConstructor(myFieldConstructorTemplate.f) }
@import helper.twitterBootstrap._
@helper.form(action = routes.Application.nextQuizPage(), 'id -> "answerRadioForm"){
@helper.inputRadioGroup(
answerRadioForm("Answer"),
options = answerList.map(answer => answer.answerID.toString -> answer.answerText),
'_label -> "Answer",
'_error -> answerRadioForm("answerID").error.map(_.withMessage("select answer")))
<button type="submit" class="btn btn-default" value="Send">
Next Question
</button>
}
@inputText(answerRadioForm("questionID"))
这确保隐式值在需要的地方可用。
始终将参数保留在模板之上并删除以下导入语句@import helper.twitterBootstrap._
这将与您自己的字段构造函数发生冲突。
@(questionList: List[Question], answerList: List[Answer], answerRadioForm: Form[Answer])
@import helper._
@implicitField = @{ FieldConstructor(myFieldConstructorTemplate.f) }
希望它能解决您的问题。
Twitter Bootstrap 结构需要准确。
像这样将 btn-group
class 包裹在 inputRadioGroup
助手周围:
<div class="btn-group" data-toggle="buttons">
@helper.inputRadioGroup(
answerRadioForm("Answer"),
options = answerList.map(answer => answer.answerID.toString -> answer.answerText),
'_label -> "Answer",
'_error -> answerRadioForm("answerID").error.map(_.withMessage("select answer")))
</div>
然后将模板替换为:
@(elements: helper.FieldElements)
<label class="btn btn-primary">
@elements.input @elements.label
</label>
<span class="errors">@elements.errors.mkString(", ")</span>
<span class="help">@elements.infos.mkString(", ")</span>
总的来说,也许另一种方法会很有趣。当您使用 fooForm("myField"...)
时,您可以在 for
循环中使用 fooForm("myField[@i]"...)
,其中 @i
是一个从 0 到有多少输入的计数器。然后你可以自己画出完整的 HTML 而不是使用隐式值。
顺便说一下,关于所有这些的 Scala 版本的文档比 Java 版本有更多的信息。参见 here。它比文档的 Java 版本包含更多关于 inputRadioGroup
的信息,但对于更好地理解所有这些内容仍然非常有用。
一些 Play Bootstrap plugin 在 GitHub 上有可用的代码,这也是有用的阅读,特别是因为它也使用隐式值。
更新
这里有几个 GitHub 项目展示了如何实现这一目标:
- 使用 Scala 版本的 Play:https://github.com/bjfletcher/play-bootstrap-radio-group
- 使用 Java 版本的 Play:https://github.com/bjfletcher/play-java-bootstrap-radio-group
结果截图:
我有某种测验系统,向用户显示一个问题和几个带有单选按钮的答案选项。
但是当我使用一个通过列表填充的 inputRadioGroup 的助手时,它看起来不再漂亮了(就像 Twitter Bootstrap)。单选按钮是内联的,而它们应该在彼此的下方。实际上我想将图标更改为更漂亮的按钮。
这是目前的样子:
因此,我尝试编写自己的自定义表单助手,但一直卡壳。我发现很难理解这方面的文档: https://www.playframework.com/documentation/2.3.x/JavaFormHelpers
首先我创建了一个名为 myFieldConstructorTemplate.scala.html
的新模板@(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>
已将其保存到 /views 文件夹。然后尝试在我看来使用它 class quiz.scala.html:
@import helper._
@import helper.twitterBootstrap._
@(questionList: List[Question], answerList: List[Answer], answerRadioForm: Form[Answer])
@helper.form(action = routes.Application.nextQuizPage(), 'id -> "answerRadioForm"){
@helper.inputRadioGroup(
answerRadioForm("Answer"),
options = answerList.map(answer => answer.answerID.toString -> answer.answerText),
'_label -> "Answer",
'_error -> answerRadioForm("answerID").error.map(_.withMessage("select answer")))
<button type="submit" class="btn btn-default" value="Send">
Next Question
</button>
}
@implicitField = @{ FieldConstructor(myFieldConstructorTemplate.f) }
@inputText(answerRadioForm("questionID"))
如果我将它放入我的模板中,我会得到一个 not found: value implicitField
-错误。
那么我怎样才能设法将单选按钮的外观更改为在下方并看起来像 Twitter Bootstrap?
[EDIT1]: 我已将导入顺序更改为建议版本:
@(questionList: List[Question], answerList: List[Answer], answerRadioForm: Form[Answer])
@import helper._
@implicitField = @{ FieldConstructor(myFieldConstructorTemplate.f) }
@import helper.twitterBootstrap._
然后我得到这个错误:
ambiguous implicit values:
both method implicitField of type => views.html.helper.FieldConstructor
and value twitterBootstrapField in package twitterBootstrap of type
=> views.html.helper.FieldConstructor match expected type
views.html.helper.FieldConstructor
我认为这与我将答案导入单选按钮的方式有关?
[EDIT2]: 现在导入的顺序是:
@(questionList: List[Question], answerList: List[Answer], answerRadioForm: Form[Answer])
@import models.Question
@import models.Answer
@import helper._
@implicitField = @{ FieldConstructor(myFieldConstructorTemplate.f) }
至此,程序编译通过。但是单选按钮看起来还是一样的。所以我试图改变设计,但效果不佳。现在看起来所有的单选按钮都融合成了一个:
这是我的模板classmyFieldConstructorTemplate.scala.html:
@(elements: helper.FieldElements)
<div class="btn-group", data-toggle="buttons">
<label for="@elements.id">@elements.label</label>
<div class="input">
<label class="btn btn-primary">
@elements.input
<span class="errors">@elements.errors.mkString(", ")</span>
<span class="help">@elements.infos.mkString(", ")</span>
</label>
</div>
</div>
[EDIT3]: 我已经根据
将 implicitField
-定义移动到文件顶部:
@(questionList: List[Question], answerList: List[Answer], answerRadioForm: Form[Answer])
@import helper._
@implicitField = @{ FieldConstructor(myFieldConstructorTemplate.f) }
@import helper.twitterBootstrap._
@helper.form(action = routes.Application.nextQuizPage(), 'id -> "answerRadioForm"){
@helper.inputRadioGroup(
answerRadioForm("Answer"),
options = answerList.map(answer => answer.answerID.toString -> answer.answerText),
'_label -> "Answer",
'_error -> answerRadioForm("answerID").error.map(_.withMessage("select answer")))
<button type="submit" class="btn btn-default" value="Send">
Next Question
</button>
}
@inputText(answerRadioForm("questionID"))
这确保隐式值在需要的地方可用。
始终将参数保留在模板之上并删除以下导入语句@import helper.twitterBootstrap._
这将与您自己的字段构造函数发生冲突。
@(questionList: List[Question], answerList: List[Answer], answerRadioForm: Form[Answer])
@import helper._
@implicitField = @{ FieldConstructor(myFieldConstructorTemplate.f) }
希望它能解决您的问题。
Twitter Bootstrap 结构需要准确。
像这样将 btn-group
class 包裹在 inputRadioGroup
助手周围:
<div class="btn-group" data-toggle="buttons">
@helper.inputRadioGroup(
answerRadioForm("Answer"),
options = answerList.map(answer => answer.answerID.toString -> answer.answerText),
'_label -> "Answer",
'_error -> answerRadioForm("answerID").error.map(_.withMessage("select answer")))
</div>
然后将模板替换为:
@(elements: helper.FieldElements)
<label class="btn btn-primary">
@elements.input @elements.label
</label>
<span class="errors">@elements.errors.mkString(", ")</span>
<span class="help">@elements.infos.mkString(", ")</span>
总的来说,也许另一种方法会很有趣。当您使用 fooForm("myField"...)
时,您可以在 for
循环中使用 fooForm("myField[@i]"...)
,其中 @i
是一个从 0 到有多少输入的计数器。然后你可以自己画出完整的 HTML 而不是使用隐式值。
顺便说一下,关于所有这些的 Scala 版本的文档比 Java 版本有更多的信息。参见 here。它比文档的 Java 版本包含更多关于 inputRadioGroup
的信息,但对于更好地理解所有这些内容仍然非常有用。
一些 Play Bootstrap plugin 在 GitHub 上有可用的代码,这也是有用的阅读,特别是因为它也使用隐式值。
更新
这里有几个 GitHub 项目展示了如何实现这一目标:
- 使用 Scala 版本的 Play:https://github.com/bjfletcher/play-bootstrap-radio-group
- 使用 Java 版本的 Play:https://github.com/bjfletcher/play-java-bootstrap-radio-group
结果截图: