在Play2的Scala模板中声明变量

59

如何在Play2 Scala模板中声明和初始化变量以供局部使用?

我有以下代码:

@var title : String = "Home"

我将模板顶部声明了它,但是它给了我这个错误:

illegal start of simple expression """),_display_(Seq[Any](/*3.2*/var)),format.raw/*3.5*/(""" title : String = "Home"
9个回答

55
@defining("foo") { title=>
  <div>@title</div>
  ...
}

基本上,你需要将你要使用它的代码块包装起来。


10
“foo”是什么意思?不是单独的这个词,而是它在哪里被使用作为参数的含义是什么? - stefan.at.kotlin
4
"foo"是要评估的表达式。您可以使用元组执行类似于“@defining((1,2,3)){case(a,b,c)=>...}”的操作,传递任何您喜欢的Scala表达式。虽然有效,但与在普通Scala代码中定义val相比,这种方法很麻烦。 - virtualeyes
@virtualeyes 如果我说错了,请纠正我,但这将定义一个值,而不是一个变量,当你尝试在模板中进一步修改它时,你会得到编译错误。 - Alexander Arendar
@AlexanderArendar 是的,Play模板是不可变的,没有任何改变任何状态的方法(即,除非您从其他地方引入可变状态)。 - virtualeyes
3
"foo"是参数。标题获取字符串“foo”的值。您还可以使用列表或任何其他类型作为参数。 - Kristóf Dombi

46

实际上,@c4k的解决方案是有效的(而且非常方便),只要您之后不尝试更改变量的值,是吗?

您只需要将此放置在模板顶部:

@yourVariable = {yourValue}

或者,如果它是一个更复杂的表达式,你可以这样做:

@yourVariable = @{yourExpression}

您甚至可以像这样使用列表进行工作:

@(listFromController: List[MyObject])
@filteredList = @{listFromController.filter(_.color == "red")}

@for(myObject <- filteredList){ ... }

对于给定的示例,这将是

@title = {Home}  //this should be at beginning of the template, right after passing in parameters

<h1> Using title @title </h1>

根据您在评论中的说法,它会被输入为HTML类型。但是,只有在您尝试再次覆盖@title时才相关,不是吗?


3
显然,在@for里面它不起作用。但是它不需要在文件的最顶部。 - nafg
2
谢谢!使用这个代替@defining感觉很棒。@defining指令根本不可读。 - yerlilbilgin
2
你在哪里看到可以使用花括号直接赋值给变量的文档了? - Jwan622

17

Scala模板支持此功能,您可以在模板中定义变量。

@import java.math.BigInteger; var i=1; var k=1

如果你想在模板中改变它的值

@{k=2}
例子
@(title:String)(implicit session:play.api.mvc.Session)
@import java.math.BigInteger; var i=1; var k=1
^
<div id='LContent_div@i'>
                     ^
  <div id='inner_div_@k'></div>
                     ^
</div>

1
它对我来说并不起作用。你能提供一个最小的示例模板来展示如何正确使用它吗? - Alexander Arendar
谢谢Govin Singh,这对我很有用,可以在HTML代码中声明变量并使用它。但是我不明白它是如何工作的,为什么我们需要导入java.math.BigInteger? - user3366706
1
@GovindSinghNagarkoti,感谢您的更新。没有导入子句会起作用吗? - Alexander Arendar
@AlexanderArendar 没有问题! - Govind Singh
@GovindSinghNagarkoti 好的,那就是一个有趣的案例。谢谢你提供的信息。 - Alexander Arendar
显示剩余2条评论

11

virtualeyes的解决方案是正确的,但也有其他可能,你可以像通常一样声明视图参数并设置默认值,在这种情况下,您将在整个模板中使用它+您仍然可以从控制器更改它的值:

@(title: String = "Home page")

<h1>Welcome on @title</h1>

控制器:

def index = Action{
    Ok(views.html.index("Other title"))
}

请注意,Java控制器无法识别模板的默认值,因此您需要每次添加它们:

public static Result index(){
    return ok(views.html.index.render("Some default value..."));
}

嘿,谢谢你提供的替代方案,但我不想将它声明为参数...我只想让它成为一个基本变量,可以在本地模板中访问,即不被继承。有没有更直接的替代方案? - travega
@virtualeyes virtualeyes 通过 @defining("foo") 展示了两种可能的方法,第三种选择是不存在的。 - biesior
1
真的吗?所以在Play2模板中声明私有实例变量的唯一方法是@defining吗?这很短视...无论如何,感谢您的输入。 - travega
实际上,就像我在某个地方写的那样-我找不到任何声明模板变量并稍后使用它们的好理由,因为这将指向静态数据,这是没有意义的(在我看来)。"控制器"应该负责定义变量-这意味着"视图"/"模板"只需负责显示。 - biesior
多模块接口框架...需要为每个最低级子模板都提供一个...我知道你还没有满足这个需求,但这并不意味着没有这样的需求。无论如何,@defining就可以了,再次感谢您的建议。 - travega

5
如果您不想用 @defining 包装所有内容,您可以这样做:
@yourVariable = { yourValue }

@defining指令在模板中确实很难读懂...


5
这将把你的变量转换为HTML元素。 - kritzikratzi
3
准确来说,那并没有解决问题。我在我的模板中尝试了它,然后这样声明的“变量”被打上了HTML类型的标签。 - Alexander Arendar

4

有一个显而易见的解决方案,看起来非常干净,有时可能更受欢迎:在模板周围定义一个作用域,在其中定义您的变量,并让该作用域生成所需的html代码,如下所示:

@{
  val title = "Home"

  <h1>Welcome on {title}</h1>
}

这种方法有一些缺点:

  • 您正在将html生成为Scala NodeSeq,有时可能会受到限制
  • 这种解决方案存在性能问题:因为@{中的代码似乎是在运行时编译的,因此为页面生成的Scala代码看起来像这样(删除了一些通常的Twirl内容):

生成的代码:

...    

Seq[Any](format.raw/*1.1*/("""<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Basic Twirl</title>
    </head>
    <body>

        """),_display_(/*9.10*/{
            val title = "Home"

                <h1>Welcome on {title}</h1>
        }),format.raw/*15.10*/("""

    """),format.raw/*17.5*/("""</body>
</html>"""))
      }
    }
  }

...

4
在twirl模板中,我建议使用定义块,因为
@random = @{
     new Random().nextInt
}

<div id="@random"></div>
<div id="@random"></div>

当多次使用时,会导致不同的值!

@defining(new Random().nextInt){ random =>
    <div id="@random"></div>
    <div id="@random"></div>
}

1
对于任何尝试Govind Singh的答案的人:
我不得不将带有变量的导入行放在参数列表下面,即:
@(title:String)(implicit session:play.api.mvc.Session)
@import java.math.BigInteger; var i=1; var k=1

工作正常。

但是,如果将包含变量over的导入语句写在导入语句之前:

@import java.math.BigInteger; var i=1; var k=1
@(title:String)(implicit session:play.api.mvc.Session)

对我没有起作用,导致了错误:

expected class or object definition

0
@isExcel= {@Boolean.valueOf(java.lang.System.getProperty(SettingsProperties.isExcel))}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接