播放/Scala模板块语句HTML输出语法与局部变量



好的,我已经为这个问题挣扎了一段时间,并且花了很多时间尝试不同的事情来做一些我用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 understanding":

@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的模板语言非常倾向于函数式编程。使用可变状态可能实现您想要实现的目标,但您可能最好顺其自然,并使用功能解决方案。

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

那么,看看你的第一个解决方案,看起来你要做的只是打印一个元素,如果它的日期与前一个不同,这是正确的吗?另一种表达方式是,你想过滤掉所有与前一个日期相同的元素。用折叠的方式来表达,我们将把这些元素折叠成一个序列(我们的初始状态),如果折叠序列的最后一个元素与当前一个元素的日期不同,我们就添加它,否则我们忽略它。

我们的折叠是这样的:

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
  }
}){
  ...
}

最新更新