[ 
https://issues.apache.org/jira/browse/VELOCITY-600?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12603913#action_12603913
 ] 

Nathan Bubna commented on VELOCITY-600:
---------------------------------------

The LoopTool makes it pretty easy to get first/last/count/index information for 
outer loops:

#foreach( $foo in $loop.watch($foos, 'foo') )
  #foreach( $bar in $loop.watch($bars) )
    Looking at \$bars[$loop.count] in \$foos[$loop.getCount('foo')]
  #end
#end

This approach works for any depth of nesting, and you don't actually even need 
the LoopTool to watch the innermost #foreach for you to have this work.

And i agree with Adrian that using the counter to access other collections is 
not the best.  This is another reason for the LoopTool, as it makes it easy to 
sync iteration over parallel collections.

#foreach( $foo in $loop.sync($foos, $bars) )
  $foo is in sync with $loop.synced  #default name for sync'ed iterator is 
"synched"
#end

Hope ya'll don't mind my hijacking this conversation for some LoopTool 
education, but really these are the sort of problems it is aimed at. :)

> #foreach & velocityCount
> ------------------------
>
>                 Key: VELOCITY-600
>                 URL: https://issues.apache.org/jira/browse/VELOCITY-600
>             Project: Velocity
>          Issue Type: Improvement
>          Components: Engine
>            Reporter: Adrian Tarau
>            Priority: Minor
>             Fix For: 1.5.1
>
>         Attachments: VELOCITY-600.patch
>
>
> velocityCount = Used in the #foreach() directive, defines the string to be 
> used as the context key for the loop count. A template would access the loop 
> count as $velocityCount.
> Knowing current version of the loop counter is very  useful, but something is 
> missing. Very often, when you generate some content base on a 
> model(JavaScript code based on some UI model) you have the need to know if 
> this is the last time when the #foreach block will be executed or not. 
> Example
> You have a collection of objects Property(bean with key, value fields) and 
> you want to generate a JavaScript object with them. The result should be like 
> this :
> {id : 1 , name = "John", ...}
> you can generate this with
> {
> #foreach($property in $properties)
>    $property.key : "$property.value" #if($velocityCount != 
> $properties.size()) , #end
> #end
> }
> You can store $properties.size() of course outside the loop.
> The template will be less verbose if I will have something like that. 
> #if($velocityHasNext) , #end.
> Instead of saving only the counter, a new variable called velocityHasNext 
> whould be populated with the result of iterator.hasNext(). This is a minor 
> modification of current #foreach directive
> while (!maxNbrLoopsExceeded && i.hasNext())
>         {
>             // TODO: JDK 1.4+ -> valueOf()
>             context.localPut(counterName , new Integer(counter));
>             context.localPut(hasNextName , i.hasNext()); <--- here is the 
> change
>             Object value = i.next();
>             context.localPut(elementKey, value);
>             /*
>              * If the value is null, use the special null holder context
>              */
>             if( value == null )
>             {
>                 if( nullHolderContext == null )
>                 {
>                     // lazy instantiation
>                     nullHolderContext = new NullHolderContext(elementKey, 
> context);
>                 }
>                 node.jjtGetChild(3).render(nullHolderContext, writer);
>             }
>             else
>             {
>                 node.jjtGetChild(3).render(context, writer);
>             }
>             counter++;
>             // Determine whether we're allowed to continue looping.
>             // ASSUMPTION: counterInitialValue is not negative!
>             maxNbrLoopsExceeded = (counter - counterInitialValue) >= 
> maxNbrLoops;
>         }
> also init should contain
> public void init(RuntimeServices rs, InternalContextAdapter context, Node 
> node)
>         throws TemplateInitException
>     {
>         super.init(rs, context, node);
>         counterName = rsvc.getString(RuntimeConstants.COUNTER_NAME);
>         hasNextName = rsvc.getString(RuntimeConstants.HAS_NEXT_NAME);
>         counterInitialValue = 
> rsvc.getInt(RuntimeConstants.COUNTER_INITIAL_VALUE);
>        ....
>     }
> This should help creating clear templates(and avoid some mistakes, sometime - 
> like using the wrong collection to test :) ).
> Thanks.
>  

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to