【问题标题】: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,如果有另一种工作方式相同并且看起来几乎像引导程序的解决方案,我会很乐意使用它。似乎更改助手并不是那么容易/直观。我感谢任何形式的帮助!

【问题讨论】:

    标签: html css twitter-bootstrap scala playframework


    【解决方案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 =&gt; views.html.helper.FieldConstructor and method implicitField of type =&gt; 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 项目展示了如何实现这一点:

    结果截图:

    【讨论】:

    • 我已将您的建议编辑到我的模板中,但仍然无法正常工作。这就是它现在的样子:i.imgur.com/7i5f85i.jpg 我发现自定义助手的文档对于像我这样的初学者来说非常混乱。文档中的更多示例或教程会有所帮助。我不知道 Scala,所以我不太了解那里的文档。在 github 示例中没有 cmets,即为什么 @containsReadonly 在那里?它是干什么用的?我怎样才能改变它?我需要改变它吗? ... 尤其是 scala、html 和 bootstrap 的混合很难掌握和理解。
    • 嗨@hamena314,只需为您准备一个项目 - 请参阅更新的答案。希望能帮助到你。 :)
    • GitHub 上现在有 Java 版本和 Scala 版本。查看更新的答案。
    • 谢谢 - 我很高兴我们终于为你解开了僵局 - 欢迎来到 Play 网络平台的世界!关于您的问题 - 是的,您可以在不使用 Play 表单助手的情况下完成所有操作。例如,对于 GitHub 项目,将表单助手替换为:
      ,那么它就 100% 没有助手。在使用 Bootstrap 时,我发现最好为复杂的部分编写我们自己的,因为 Play form helpers 的 HTML 结构有时不能很好地与 Bootstrap 的预期结构配合使用。随时使用。享受:)
    • Re radio-group - 我想你在考虑按钮组 -> getbootstrap.com/javascript/#buttons-checkbox-radio(你可以使用与我的项目类似的技术来使用它)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-02
    • 2011-02-07
    • 2015-05-10
    • 2013-01-11
    • 2012-03-07
    相关资源
    最近更新 更多