Declare variable in a Play2 scala template
Asked Answered
T

9

59

How do you declare and initialize a variable to be used locally in a Play2 Scala template?

I have this:

@var title : String = "Home"

declared at the top of the template, but it gives me this error:

illegal start of simple expression """),_display_(Seq[Any](/*3.2*/var)),format.raw/*3.5*/(""" title : String = "Home"
Terminal answered 20/8, 2012 at 0:48 Comment(0)
U
55
@defining("foo") { title=>
  <div>@title</div>
  ...
}

basically, you have to wrap the block in which you are going to use it

Unriddle answered 20/8, 2012 at 1:1 Comment(5)
what does the "foo" mean? not the word as itself, but where this parameter is used?Hbomb
"foo" is the expression to evaluate. You can do things like "@defining( (1,2,3) ) { case(a,b,c)=> ... }" using tuples, passing in any scala expression you like. Works, but is a pain in the ... compared to defining a val in place as you can do in normal scala codeUnriddle
@Unriddle correct me if I am wrong, but this will define a value, not a variable and when you will try to modify it further in th template you will get compilation error.Sepia
@AlexanderArendar yes, play templates are immutable, no way to change the state of anything (i.e. unless you pull in mutable state from elsewhere)Unriddle
"foo" is the parameter. title gets the String "foo" value. You could also use a list or any other types as parameter.Mata
M
47

Actually, @c4k 's solution is working (and quite convenient) as long as you don't try to change the variable's value afterwards, isn't it?

You simply place this at the top of your template:

@yourVariable = {yourValue}

or, if it's a more complicated expression, you do this:

@yourVariable = @{yourExpression}

You can even work with things like lists like that:

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

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

For the given example, this would be

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

<h1> Using title @title </h1>

In the comments you said, that it gets typed to HTML type. However, that is only relevant if you try to overwrite @title again, isn't it?

Magnificent answered 4/8, 2015 at 9:11 Comment(3)
Apparently it doesn't work inside a @for. However it doesn't need to be all the way at the top of the file.Congo
Thank you!!! using this instead of the @defining felt great. the @defining directive is not readable at allJill
Where is this documented that you can just assign a variable using curly braces?Upwind
J
17

scala template supports this, you can define variable in template

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

if you want to change its value in template

@{k=2}

example

@(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>
Jervis answered 28/1, 2014 at 5:37 Comment(7)
it does not really work for me. could you provide a minimal example template to show how to properly use it?Sepia
Thanks Govin Singh, It works for me to declare a variable and use it in html code.. but I dont understand how it works, why should we import java.math.BigInteger?Pen
@GovindSinghNagarkoti, thanks for update. Will it work without import clause?Sepia
@AlexanderArendar noops!Jervis
@GovindSinghNagarkoti ok, that is an intersting case then. Thanks for info.Sepia
Great option! How can I do that, but for strings?Deacon
Ok, figured out about string... How can I do that, but for multiple variables when they go to another line?Deacon
C
11

virtualeyes' solution is the proper one, but there is also other possibility, you can just declare a view's param as usually with default value, in such case you'll have it available for whole template + you'll keep possibility for changing it from the controller:

@(title: String = "Home page")

<h1>Welcome on @title</h1>

controller:

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

Note that Java controller doesn't recognise templates' default values, so you need to add them each time:

public static Result index(){
    return ok(views.html.index.render("Some default value..."));
}
Cyd answered 20/8, 2012 at 6:34 Comment(5)
Hey thanks for the alternative but I don't want to declare it as a parameter... I just want it to be a straight out basic variable that I can access within the local template i.e. not to be inherited. Is there a straight forward alternative to this?Terminal
@Unriddle virtualeyes showed the way to do that with @defining("foo"), there are only two possible ways. Third alternative doesn't exist.Cyd
Really? So @defining is the only way to declare an private instance variable in a Play2 template?? That's pretty short sighted... Anyway thx for yer input.Terminal
Really, as I wrote somewhere - I can't find any good reason for declaring variables in the template and using them later, as it will be pointing to static data and it doesn't make sense (IMHO). Controller should care about defining variables - that means, that view/template should only care about displaying them.Cyd
Multi-modular interface frameworks... Requires one for every lowest level sub template... I understand you haven't met a need for one but that doesn't mean there isn't one. Anyways @defining will do thx again for your input.Terminal
S
5

If you don't want to wrap all your content with @defining, you can do this :

@yourVariable = { yourValue }

The @defining directive is really unreadable in a template...

Stoush answered 8/3, 2014 at 19:32 Comment(2)
this will turn your variable into a html thingieCandace
precisele, that does not solve the problem. I tried it in my template and then such desclared "variable" gets typed to HTML type.Sepia
R
4

There is one obvious solution which looks quite clean and may be preferred sometimes: define a scope around the template, define your variable inside of it, and let the scope produce the html code you need, like this:

@{
  val title = "Home"

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

This has some drawbacks:

  • you are generating your html as Scala NodeSeq this way, which may be limiting sometimes
  • there is a performance issue with this solution: the code inside of @{ seems to be compiled runtime, because the Scala code generated for the page loooks like this (some usual Twirl stuff deleted):

The generated code:

...    

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>"""))
      }
    }
  }

...
Resolve answered 17/10, 2016 at 9:48 Comment(0)
W
4

In twirl templates I would recommend using the defining block, because the

@random = @{
     new Random().nextInt
}

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

would result in different values when used multiple times!

@defining(new Random().nextInt){ random =>
    <div id="@random"></div>
    <div id="@random"></div>
}
Wolf answered 13/12, 2018 at 16:40 Comment(0)
G
1

For anyone who tries the answer of Govind Singh:
I had to put the import line with the variable under the parameter list, i.e.

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

works.

But putting the import with the variable over the import statement, i.e.

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

did not work for me and resulted in the error:

expected class or object definition
Gerta answered 16/7, 2021 at 11:41 Comment(0)
A
0
@isExcel= {@Boolean.valueOf(java.lang.System.getProperty(SettingsProperties.isExcel))}
Abstraction answered 3/10, 2016 at 11:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.