[2.0] Scala Templates - local template scope variables

11,593 views
Skip to first unread message

Brian Nesbitt

unread,
Dec 1, 2011, 9:27:24 AM12/1/11
to play-fr...@googlegroups.com
Is there any way of creating local template scoped variables?  I have tried several different ways but can't get something that I think should be easy to work.
Say you have firstname and lastname as parameters and in a few places you want to just output name.

@(firstname: String, lastname: String)

@fullname = firstname + " " + lastname

<p>Hi there @fullname !</p>

Its not a great example, but can you do this without using a local function?
Also like @i = 5 sorta thing then @i += 1 other places?  I tried something like this but it auto makes it a "val" so it can't be reassigned.

Pascal Voitot Dev

unread,
Dec 1, 2011, 9:37:42 AM12/1/11
to play-fr...@googlegroups.com
Did you try?

@{val name = customer.firstName + customer.lastName}

@name

Pascal


--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To view this discussion on the web visit https://groups.google.com/d/msg/play-framework/-/KDZsvAes2skJ.
To post to this group, send email to play-fr...@googlegroups.com.
To unsubscribe from this group, send email to play-framewor...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.

Brian Nesbitt

unread,
Dec 1, 2011, 10:26:24 AM12/1/11
to play-fr...@googlegroups.com
Doing:

@{val name = "brian"}
@name 

Generates compiler error: "not found: value name"... the name variable is scoped to that code block.

Doing:

@{val name = "brian"; name}

works but only for that code block and its not really a variable.

Doing:

@name = {brian}
@name

Works fine because its like a function...but what about numbers:

@i=5
@i

doesn't work

but for numbers Doing:

@i={5}
@i+1

Or some combination there of doesn't really work as it gives you an html block "5+1" rather than integer 6.

@inc(v:Int) = @{
  v + 1
}

@{
  var i = 0
  inc(i)
}
@i

Gives a compile error for the last line:  not found: value i.... because its local to the code block

Of course if you specify an optional parameter to the template with a default value (that no one else uses) you can use that as a local variable but seems wrong.

Pascal Voitot Dev

unread,
Dec 1, 2011, 10:49:06 AM12/1/11
to play-fr...@googlegroups.com
I think we need help from someone in the play team :D

Apparently this is a limitation known in Play1.2.x Scala template. Declaring variables was not yet supported apparently.
It would be a useful feature IMO.

Pascal

--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To view this discussion on the web visit https://groups.google.com/d/msg/play-framework/-/n58cr5XLmCUJ.

Julien Richard-Foy

unread,
Dec 1, 2011, 11:00:31 AM12/1/11
to play-fr...@googlegroups.com
You can use the following, I guess:

@defining(customer.firstName + customer.lastName) { fullname =>

Pascal Voitot Dev

unread,
Dec 1, 2011, 11:12:29 AM12/1/11
to play-fr...@googlegroups.com
A question: do you think it would be impossible to provide a way to define a variable and reuse it later in the script?

@{ var i=0 }
...
@{ i+=5 }
...
@i

Pascal

--
You received this message because you are subscribed to the Google Groups "play-framework" group.

Guillaume Bort

unread,
Dec 1, 2011, 12:17:01 PM12/1/11
to play-fr...@googlegroups.com
No.

>> @defining(customer.firstName + customer.lastName) { fullname =>
>>  <p>Hi there @fullname !</p>
>> }

Is the correct way to do it.

--
Guillaume Bort

Pascal Voitot Dev

unread,
Dec 1, 2011, 12:20:28 PM12/1/11
to play-fr...@googlegroups.com
I'm trying to see the right behaviour to have when writing templates...
you really must think in a functional way, isn't it?

Richard

unread,
Mar 30, 2012, 5:23:09 AM3/30/12
to play-fr...@googlegroups.com
Hi Guillaume!

Wouldn't it be an idea to add basic stuff like this in a cheat sheet like in play 1.x documentation.
I'm a java programmer and am facing a lot of these issues. (thinking from object to functional programming)..

/Richard

jsamot

unread,
Apr 24, 2012, 4:38:43 AM4/24/12
to play-framework
The below question was an interesting one, which I was searching for
an answer to:

>>>> From: Pascal Voitot Dev <pascal.voitot....@gmail.com>
>>>> Date: Thu, 1 Dec 2011 17:12:29 +0100
>>>> A question: do you think it would be impossible to provide a way to define
>>>> a variable and reuse it later in the script?
>>>> @{ var i=0 }
>>>> @{ i+=5 }
>>>> @i

As far as I understand, the below reply was an answer to the above
question, or maybe I misunderstood that ?

>>> From: Guillaume Bort <guillaume.b...@gmail.com>
>>> Date: Thu, 1 Dec 2011 18:17:01 +0100

>>>> @defining(customer.firstName + customer.lastName) { fullname =>
>>>> <p>Hi there @fullname !</p>
>>>> }

>>> Is the correct way to do it.

So this was the correct way to do what, I mean what is being defined
above ?
Maybe a constant named "fullname" ?

It is not clear to me at all what the above syntax mean, and when it
could be a better approach than doing the following for reusing the
concatenation of a first and last name:

@getFullName(customer: Customer) = {
<p>Hi there @customer.firstName + @customer.lastName !</p>
}

How can the "defining" construct be used for creating an increasing
variable as in the question at the top of this message above ?

For example, if you want to generate a html table with every second
row being in different colors, you might want to define a css class
"row0" and "row1" and then render the class attribute with a module
operator dividing with and returning one or zero, such as
class="row@{(rowCount++)%2}" but how would you increase a variable in
Scala play ?
Is it impossible to use a variable like this in Scala playframework ?
If so, is this only a current limitation or is not even intended to
become possible in a next version ?

What is the recommended way of achieveing alternating row colors, if
the above kind of construct with module operator and a counter is not
possible ?

Even if there is a better way of doing it, I am still interested in
the answer about how to use varaiables in a scala play template view,
since there may be other situations where it is useful to use
scriptings for a simple thing.

(
Some people might think that "code" in views are always ugly and dirty
and should even be prevented from being possible, but I would rather
say that the pragmatic reality is that when you are learning a new
framework you do not want to get stuck in a feeling that the framework
prevents you from doing simple things.
I mean, it is kind of hard to convince the boss that I should be
allowed to spend time in developing web applications with Scala Play
framework, when you keep getting stuck in this kind of things that
e.g. a PHP programmer could fix very quickly, while I have to search
for hours about a clean solution of this kind of simple thing (such as
making every second row in a table in different colors).
In other words, what I am trying to say is that I think scripting
(including variables) should be _possible_ which is not the same thing
as recommending it to being frequently used.
)

William Barksdale

unread,
Jun 3, 2012, 2:00:51 PM6/3/12
to play-fr...@googlegroups.com
I really want to second what jsamot said above. This feature would really make life a lot easier, to just be able to define a variable in place. The @defining syntax is very confusing and ugly imho. 

Can we expect to see this functionality in later releases?

Robin Green

unread,
Jun 4, 2012, 2:31:50 PM6/4/12
to play-fr...@googlegroups.com
I hate to sound like a broken record, but if you are defining a large number of variables (as opposed to parameters) in your templates, that is probably a design smell. You should probably use Scala or Java code for that logic instead.

--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To view this discussion on the web visit https://groups.google.com/d/msg/play-framework/-/2cVpyGP2dXAJ.

johanandren

unread,
Jun 7, 2012, 4:05:58 PM6/7/12
to play-fr...@googlegroups.com
To answer the question about alternating row colors, here you have two examples in a block defining the list they are looping over:

 @defining(List(1,2,3,4,5,6)) { items => 

    <table>
      @items.zipWithIndex.map { case (item, index) =>
        <tr class="@if((index + 1) % 2 == 0){even}else{odd}">
          <td>@item</td>
        </tr>
      }
    </table>
    

    <table>
      @for(i <- 0 until items.size) {
        <tr class="@if((i + 1) % 2 == 0){even}else{odd}">
          <td>@items(i)</td>
        </tr>
      }
    </table>
  } 


The first one uses zipWithIndex which transforms a list to a list of pairs/tuples containing the item and the index of each position, the second one is a regular imperative foor loop.

Hope it helps you understand why defining mutable state is not really needed.

Manish Kumar

unread,
Jun 16, 2012, 4:56:28 PM6/16/12
to play-fr...@googlegroups.com
Hi, 

I'm trying to declare multiple variables using the @defining construct.

@defining("Hello") { p => 
@p 
}

The above code works fine, but I dont know how to declare multiple variables using this syntax. I tried this:

@defining(("Hello", "World")) { (p, q) => 
@p 
@q 
}

But this gives me error: wrong number of parameters; expected = 1

I don't want to write nested @defining blocks. Is there any other way?


Thanks,
Manish

Pascal Voitot Dev

unread,
Jun 17, 2012, 4:23:42 AM6/17/12
to play-fr...@googlegroups.com
You should add the case before your (p,q)

@defining(("Hello", "World")) { case (p, q) => 
@p 
@q 
}

It's as if you wrote:

@defining(("Hello", "World")) { v => v match { case (p, q) => 
@p 
@q 
} }

Pascal

--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To view this discussion on the web visit https://groups.google.com/d/msg/play-framework/-/dwb7blKESxcJ.

Pascal Voitot Dev

unread,
Jun 17, 2012, 4:29:44 AM6/17/12
to play-fr...@googlegroups.com
I agree with you.
Scala templates are built in a simplified functional way. This requires a few mental exercises at the beginning because lots of people are used to thinking in an imperative way. But functional design always makes thing more robust and cleaner since you must structure your code and it forces you not to create artificial variables that are just there to make your stuff work. It's worth the try.

Pascal

Kenji Matsuoka

unread,
Jun 21, 2012, 8:45:40 PM6/21/12
to play-fr...@googlegroups.com
So, is there something non-functional about defining local vals inside a function?

I'm currently prototyping the conversion of a rather large, high-traffic website from PHP/Zend to Play 2, and the lack of local vals is one of Play 2's most obvious shortcomings.  The @defining syntax is a little verbose, in my opinion, especially for multiple vals.  And I don't like having to introduce more levels of nesting.

As far as I can tell, there's no fundamental reason not to support a syntax like this:

@(i: Int, j: Int)
@val k = i + j

I can insert the val definition in the generated scala and it compiles fine.


To post to this group, send email to play-framework@googlegroups.com.
To unsubscribe from this group, send email to play-framework+unsubscribe@googlegroups.com.

For more options, visit this group at http://groups.google.com/group/play-framework?hl=en.

--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To post to this group, send email to play-framework@googlegroups.com.
To unsubscribe from this group, send email to play-framework+unsubscribe@googlegroups.com.

Pascal Voitot Dev

unread,
Jun 22, 2012, 3:03:55 AM6/22/12
to play-fr...@googlegroups.com
On Fri, Jun 22, 2012 at 2:45 AM, Kenji Matsuoka <ken...@gmail.com> wrote:
So, is there something non-functional about defining local vals inside a function?

I'm currently prototyping the conversion of a rather large, high-traffic website from PHP/Zend to Play 2, and the lack of local vals is one of Play 2's most obvious shortcomings.  The @defining syntax is a little verbose, in my opinion, especially for multiple vals.  And I don't like having to introduce more levels of nesting.

I understand your point of view but the aim is also to build your template in a safe way... it forces you to build variables that are just convenient locally within the template. No logic in the template at all.
 

As far as I can tell, there's no fundamental reason not to support a syntax like this:

@(i: Int, j: Int)
@val k = i + j

I can insert the val definition in the generated scala and it compiles fine.


Yes it compiles but you can't reuse this val afterwards!
 
To view this discussion on the web visit https://groups.google.com/d/msg/play-framework/-/NyvJMy_BGvwJ.

To post to this group, send email to play-fr...@googlegroups.com.
To unsubscribe from this group, send email to play-framewor...@googlegroups.com.

Kenji Matsuoka

unread,
Jun 22, 2012, 7:44:35 PM6/22/12
to play-fr...@googlegroups.com
What do you mean by can't reuse?  I can use the val inserted as I described just like a parameter to the template.  

How is defining a val different from defining a function -- which can certainly contain logic -- apart from the val only needing to be evaluated once?

@(i: Int, j: Int)
@divides = @{ i % j == 0 }

Tim Holt

unread,
Mar 25, 2013, 12:50:58 PM3/25/13
to play-fr...@googlegroups.com
Somewhat an old post to reply to, but I feel the need to comment.

Yes, that's a very nice bit of code.  The problem is, it is confusing to anyone but a Scala knowledgeable developer.  And a very common thing in my experience with web development is that not all people writing templates are coders - they are in fact designers who know their HTML and content creation very well, but they do not know their programming well.  This solution requires a really good understanding of Scala, which designers won't always have.

Albert Kwong

unread,
Jun 25, 2013, 8:26:38 AM6/25/13
to play-fr...@googlegroups.com
I am new to play and new to scala template.  I am also looking for a way to define local variables in templates.  So from reading this thread I guess there's no way to do it without some tricks, right?

So, I end up passing a Map to the template as parameter for storing local variables.  Are you guys doing the same or do you have better ways?  Thanks.

@(vars:utils.VarMap)

@vars.put("newVar", "some value")

@vars.get("newVar")



package utils;

import java.util.HashMap;
import java.util.Map;

/**
 * A simple hack to use variables in scala templates. This is necessary because
 * the standard Map.put(K,V) returns V.
 */
public class VarMap {

private Map<String, Object> vars = new HashMap<String, Object>();

public void put(String key, Object value) {
vars.put(key, value);
}

public Object get(String key) {
return vars.get(key);
}
}


Guillaume Bort

unread,
Jun 25, 2013, 8:33:38 AM6/25/13
to play-fr...@googlegroups.com

On Tue, Jun 25, 2013 at 2:26 PM, Albert Kwong <alb...@mba.hk> wrote:
Are you guys doing the same or do you have better ways?

The best way is to not rely on variable at all and to embrace the functional way of doing stuff instead. It's way much straightforward, especially for a template engine.


--

Sheng Huang

unread,
Dec 12, 2013, 1:56:32 PM12/12/13
to play-fr...@googlegroups.com
I also think the grammar of Scala/Play is so difficult to follow and ugly and very different from other languages.

Haoyi Li

unread,
Dec 12, 2013, 2:38:39 PM12/12/13
to play-fr...@googlegroups.com
I made https://github.com/lihaoyi/scalatags for mostly that reason. I found it strange to try and force things into XML syntax (while other people are trying to do their best to run away from XML syntax) resulting in both crufty markup (XML) and crufty pseudo-Scala code within that markup. With Scalatags, I think things look far better.

Scalatags only works in Scala, but it would be pretty trivial (~200 lines of code) to duplicate the bulk of the functionality in a Java library.


On Thu, Dec 12, 2013 at 10:56 AM, Sheng Huang <shenghu...@gmail.com> wrote:
I also think the grammar of Scala/Play is so difficult to follow and ugly and very different from other languages.

--
You received this message because you are subscribed to the Google Groups "play-framework" group.
To unsubscribe from this group and stop receiving emails from it, send an email to play-framewor...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Govind Singh

unread,
Feb 12, 2014, 10:55:09 AM2/12/14
to play-fr...@googlegroups.com

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

try this in scala template

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

if you want string then

@import java.lang.String; val name="template"


 
 
 

Alexander Aristov

unread,
Jun 24, 2014, 4:00:34 PM6/24/14
to play-fr...@googlegroups.com

Really awesome example which helped me to workaround problem if implementing counter in lists with the for statement. And dont tell me about zipWithIndex. It works but it brakes order of elements that is absolutely not acceptable. With these variables I have managed to implement it.
Reply all
Reply to author
Forward
0 new messages