Velocity
  1. Velocity
  2. VELOCITY-773

Provide locally scoped #set variables

    Details

    • Type: Improvement Improvement
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Not a Problem
    • Affects Version/s: 1.7-beta1
    • Fix Version/s: None
    • Component/s: Engine
    • Labels:
      None

      Description

      Consider this snippet:
      <!-- Generated pushbutton groups -->
      #foreach ($group in $form.pushbuttonGroups)
      <div class="die-button-group" style="#coordinates($group)">

        • *##foreach ($groupChild in $group.children)
        • *##if (!$velocityHasNext)#set($turnPaddingOff = 'style="padding-bottom: 0px;"')#end
        • *##if ($groupChild.class.simpleName == "Pushbutton")
        • *#<div $!turnPaddingOff>
        • *#<button type="submit" name="$groupChild.name" value="$groupChild.value" onclick="loadSubsequent()">#label($groupChild.label)</button>
        • *#</div>
        • *##end
        • *##end
          </div>
          #end

      There is an inherent bug. After the first run of the outer foreach, the var turnPaddingOff is still available and will always set in the div tag. There is only one workaround. At the end of the outer foreach you have to set it to ''.

      #set should be available as a locally scoped thing in #foreach or other constructs.

        Activity

        Hide
        Nathan Bubna added a comment -

        No. This is by design. There are no more implicit scopes in Velocity 1.7+ All variables are now global scoped by default. Scoping is now done explicitly. You can turn on the explicit scopes you want/need as listed here:

        http://velocity.apache.org/engine/devel/developer-guide.html#Velocity_Configuration_Keys_and_Values

        Then use them explicitly:

        #set( $macro.foo = 'bar' )## will vanish when macro is done rendering

        Show
        Nathan Bubna added a comment - No. This is by design. There are no more implicit scopes in Velocity 1.7+ All variables are now global scoped by default. Scoping is now done explicitly. You can turn on the explicit scopes you want/need as listed here: http://velocity.apache.org/engine/devel/developer-guide.html#Velocity_Configuration_Keys_and_Values Then use them explicitly: #set( $macro.foo = 'bar' )## will vanish when macro is done rendering
        Hide
        Michael Osipov added a comment -

        Nathan, this solved my problem. Thanks. Your comment though is slightly incorrect. According to the docs, local scope for foreach is always on by default. I simply did $foreach.turnPaddingOff

        Show
        Michael Osipov added a comment - Nathan, this solved my problem. Thanks. Your comment though is slightly incorrect. According to the docs, local scope for foreach is always on by default. I simply did $foreach.turnPaddingOff
        Hide
        Nathan Bubna added a comment -

        You're right, $foreach is always on, as it (and its special properties) are heavily used.

        Show
        Nathan Bubna added a comment - You're right, $foreach is always on, as it (and its special properties) are heavily used.
        Hide
        Christopher Schultz added a comment -

        What implications does this have for code like this:

        #foreach($foo in $foos)
        #set($foreach.someVar = 'some value')
        #foreach($bar in $bars)
        .. terribly interesting stuff
        #end

        $foreach.someVar
        #end

        Does each foreach loop create a nested Context in which vars are defined and then cleared? Otherwise, the behavior of nested foreach loops might surprise some people.

        Show
        Christopher Schultz added a comment - What implications does this have for code like this: #foreach($foo in $foos) #set($foreach.someVar = 'some value') #foreach($bar in $bars) .. terribly interesting stuff #end $foreach.someVar #end Does each foreach loop create a nested Context in which vars are defined and then cleared? Otherwise, the behavior of nested foreach loops might surprise some people.
        Hide
        Nathan Bubna added a comment -

        No, there is no nested context. What you get is a nested scope. So, your example works just fine, and if you want access to someVar in the inner loop, you do it explicitly, of course:

        #foreach($a in $as)
        #set( $foreach.foo = 'bar')
        #foreach($b in bs)
        $foreach.parent.foo
        #end
        $foreach.foo
        #end

        Explicit is the name of the game now for scoping variables. It may mean you have to type a few extra characters, but it spares a great deal of complexity at all levels. KISS

        Show
        Nathan Bubna added a comment - No, there is no nested context . What you get is a nested scope . So, your example works just fine, and if you want access to someVar in the inner loop, you do it explicitly, of course: #foreach($a in $as) #set( $foreach.foo = 'bar') #foreach($b in bs) $foreach.parent.foo #end $foreach.foo #end Explicit is the name of the game now for scoping variables. It may mean you have to type a few extra characters, but it spares a great deal of complexity at all levels. KISS

          People

          • Assignee:
            Unassigned
            Reporter:
            Michael Osipov
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development