【问题标题】:Play/Scala Template Block Statement HTML Output Syntax with Local VariablePlay/Scala 模板块语句 HTML 输出语法与局部变量
【发布时间】:2015-08-18 19:56:24
【问题描述】:

好的,我一直在纠结这个问题,并且花了很多时间尝试不同的事情来做一些我使用 PHP 很容易做到的事情。

我正在尝试迭代列表,同时在本地跟踪变量,同时吐出 HTML 以尝试填充表格。

尝试 #1:

@{
    var curDate : Date = null
    for(ind <- indicators){
        if(curDate == null || !curDate.equals(ind.getFirstFound())){
            curDate = ind.getFirstFound()
            <tr><th colspan='5' class='day'>@(ind.getFirstFound())</th></tr>
            <tr><th>Document ID</th><th>Value</th><th>Owner</th><th>Document Title / Comment</th></tr>
        }
    }
}

我也尝试使用 scala 块语句来允许我将 curDate 作为变量保留在创建的范围内。此块正确维护 curDate 状态,但不允许我向 DOM 输出任何内容。由于我未转义,随机抛出 HTML,我实际上并没有期望它会编译,但确实如此。尽管决策结构在服务器上正确执行,但这个循环只是在 DOM 上没有放置任何内容。

我尝试使用@Html('...') 进行转义,但产生了编译错误。

尝试 #2:

很多谷歌搜索让我找到了“理解”:

@for(ind <- indicators; curDate = ind.getFirstFound()){
    @if(curDate == null || !curDate.equals(ind.getFirstFound())){
        @(curDate = ind.getFirstFound())
    }
    <tr><th colspan='5' class='day'>@(ind.getFirstFound())</th></tr>
    <tr><th>Document ID</th><th>Value</th><th>Owner</th><th>Document Title / Comment</th></tr>
}

如果没有这个块中的 if 语句,这是我最接近我真正想做的事情,但显然我不允许重新分配非引用类型,这就是为什么我希望尝试 #1 的引用声明curDate : Date = null 会工作。这种尝试让我获得了页面上的 HTML(同样,如果我删除了嵌套的 if 语句)但没有让我获得

我的问题是,我该如何实现这个意图?我非常痛苦地意识到我缺乏 Scala 知识,而 Play 模板语法加剧了这种情况。我不知道该怎么办。

提前致谢!

【问题讨论】:

    标签: scala playframework playframework-2.0


    【解决方案1】:

    Play 的模板语言非常适合函数式编程。使用可变状态可能实现您想要实现的目标,但您最好顺其自然,并使用功能解决方案。

    如果您想在函数式编程中的循环迭代之间保持状态,可以通过折叠来完成 - 您从某个状态开始,在每次迭代中,您会获得前一个状态和下一个元素,然后您然后根据这两件事返回新的状态。

    所以,看看您的第一个解决方案,您似乎只是在日期与前一个不同的情况下打印一个元素,对吗?另一种表达方式是您要过滤掉所有日期与前一个日期相同的元素。用折叠表示,我们将把元素折叠成一个序列(我们的初始状态),如果折叠序列的最后一个元素与当前的日期不同,我们添加它,否则我们忽略它。

    我们的折叠看起来像这样:

    indicators.foldLeft(Vector.empty[Indicator]) { (collected, next) =>
      if (collected.lastOption.forall(_.getFirstFound != next.getFirstFound)) {
        collected :+ next
      } else {
        collected
      }
    }
    

    为了解释上面的内容,我们折叠成Vector,因为Vector 有固定时间追加,最后,List 有n 个时间。如果collected 中没有最后一个元素,forall 将返回 true,否则,如果传入的 lambda 计算结果为 true,它将返回 true。而在 Scala 中,== 调用 .equals(在进行空检查之后),因此您不需要在 Scala 中使用 .equals

    因此,将其放入模板中:

    @for(ind <- indicators.foldLeft(Vector.empty[Indicator]) { (collected, next) =>
      if (collected.lastOption.forall(_.getFirstFound != next.getFirstFound)) {
        collected :+ next
      } else {
        collected
      }
    }){
      ...
    }
    

    【讨论】:

    • 非常感谢您的耐心等待,这解决了我的问题。对于阅读本文的其他人,我遇到了实现此答案的问题,其中编译器认为我想使用java.util.Vector 类,因此找不到我们实际想要使用scala.collection.immutable.Vectorempty 成员,所以确保定义导入或指定类型。
    • 您也可以使用 IndexedSeq,它默认为 Vector,它不应该与 Java 导入冲突。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多