如何为动态生成的内容编写自定义表单助手模板?
Posted
技术标签:
【中文标题】如何为动态生成的内容编写自定义表单助手模板?【英文标题】:How to write a custom form helper template for dynamically generated content? 【发布时间】:2015-08-29 15:20:52 【问题描述】:我有某种测验系统,向用户显示一个问题和几个带有单选按钮的答案选项。
但是当我使用一个通过列表填充的 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 文件夹。然后尝试在我的视图类中使用它 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
-error。
那么,我怎样才能设法将单选按钮的外观更改为下方并看起来像 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)
这样,程序就可以编译了。但是单选按钮看起来还是一样的。所以我试图改变设计,但不太奏效。现在看起来所有的单选按钮都融合成一个了:
这是我的模板类myFieldConstructorTemplate.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]: 我已经根据to the last answer 更改了我的班级,但单选按钮仍然相互融合。所以我想指出,我并不执着于使用inputRadioGroup from the playframework helper,如果有另一种工作方式相同并且看起来几乎像引导程序的解决方案,我会很乐意使用它。似乎更改助手并不是那么容易/直观。我感谢任何形式的帮助!
【问题讨论】:
【参考方案1】:将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"))
这确保隐式值在需要的地方可用。
【讨论】:
如果我这样做,我会在@(questionList: List[Question], answerList: List[Answer], answerRadioForm: Form[Answer])
行中得到一个编译错误not found: value questionList
。如果我将线 @implicitField = ...
移动到 @questionList:...
线下方,我会收到此错误:ambiguous implicit values: both value twitterBootstrapField in package twitterBootstrap of type => views.html.helper.FieldConstructor and method implicitField of type => views.html.helper.FieldConstructor match expected type views.html.helper.FieldConstructor
我试过你的版本,但一直出错,请参阅我编辑的帖子。【参考方案2】:
始终将参数保留在模板之上并删除以下导入语句@import helper.twitterBootstrap._
这将与您自己的字段构造函数冲突。
@(questionList: List[Question], answerList: List[Answer], answerRadioForm: Form[Answer])
@import helper._
@implicitField = @ FieldConstructor(myFieldConstructorTemplate.f)
希望它能解决您的问题。
【讨论】:
我也试过你的版本,但我一直收到错误。请查看我的编辑。 删除以下导入语句@import helper.twitterBootstrap._ 并尝试。 删除了 import 语句,现在我的程序可以编译了。但它看起来与我发布的图片完全相同。单选按钮仍然是内联的,文本仍然是粗体,看起来不像引导程序。 @hamena314 您所看到的是默认行为,为了按照您的方式进行操作,您需要包含相应的引导 css 选择器。 @hamena314 看看这个link 在 twitter bootstrap 中设置单选按钮。【参考方案3】:Twitter Bootstrap 结构需要准确。
将btn-group
类包裹在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结果截图:
【讨论】:
我已将您的建议编辑到我的模板中,但仍然无法正常工作。这就是它现在的样子:i.imgur.com/7i5f85i.jpg 我发现自定义助手的文档对于像我这样的初学者来说非常混乱。文档中的更多示例或教程会有所帮助。我不知道 Scala,所以我不太了解那里的文档。在 github 示例中没有 cmets,即为什么@containsReadonly
在那里?它是干什么用的?我怎样才能改变它?我需要改变它吗? ... 尤其是 scala、html 和 bootstrap 的混合很难掌握和理解。
嗨@hamena314,只需为您准备一个项目 - 请参阅更新的答案。希望能帮助到你。 :)
GitHub 上现在有 Java 版本和 Scala 版本。查看更新的答案。
谢谢 - 我很高兴我们终于为你解开了僵局 - 欢迎来到 Play 网络平台的世界!关于您的问题 - 是的,您可以在不使用 Play 表单助手的情况下完成所有操作。例如,对于 GitHub 项目,将表单助手替换为:
Re radio-group - 我想你在考虑按钮组 -> getbootstrap.com/javascript/#buttons-checkbox-radio(你可以使用与我的项目类似的技术来使用它)。以上是关于如何为动态生成的内容编写自定义表单助手模板?的主要内容,如果未能解决你的问题,请参考以下文章
如何为 NSManagedObject 子类编写自定义访问器?