Play/Scala 模板块语句 HTML 带局部变量的输出语法

Play/Scala Template Block Statement HTML Output Syntax with Local Variable

好的,我已经为此苦苦挣扎了一段时间,并且花了很多时间尝试不同的事情来做一些我使用 PHP.

可以轻松完成的事情

我正在尝试遍历列表,同时在本地跟踪变量,同时吐出 HTML 试图填充 table。

尝试 #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:

大量 google 搜索让我找到了 "for comprehension":

@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 模板语法加剧了这种情况。我不知道该怎么做。

提前致谢!

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

如果你想在函数式编程中的循环迭代之间保持状态,可以通过折叠来实现——你从某个状态开始,在每次迭代中,你得到前一个状态和下一个元素,然后你 return 基于这两件事的新状态。

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

我们的弃牌是这样的:

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

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

因此,将其放入模板中:

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