Search This Blog

Monday, December 31, 2012

THE Framework - Iterative Elements FAIL

   Iterative elements are not going well.  Here are notes on this:  

31 Dec., 2012
 ------------------  
   Worked on the iterative problem.  I tried creating a custom foreach Directive for Velocity.  First, the Parser will not accept an underscore in the directive name.  I had wanted to use the_foreach, but that's no good.  Second, the Parser will only allow the argument syntax ( $item in $list ) in the foreach Directive. It's a hard coded literal in the Parser.

   So, I tried creating a subclass and/or a wrapper for the foreach Directive.  The name can't be anything but foreach.  The next effort was a subclass that copied the foreach Directive code entirely and modifying from there.  This required creating a ForeachScope wrapper class as well to allow access to the private members of the scope class.  The class uses the foreach name and is found before the Foreach class by the Parser.  This is fragile.  It does allow additional arguments to be passed in.  It accepts an optional boolean argument to indicate whether to perform the nesting constructions.  All of this could break with changes to Velocity.

   The idea was to have a variable called currentLabel and a stack of currentLabels in the Velocimacro library. On the call of a nested foreach, the currentLabel would be pushed on the scope stack.  The currentLabel would have the value of the list argument appended to it.  As the loop ended, the currentLabel would be replaced by popping the top value off the stack.  This allows nested scoping.

   Inside the body of the foreach loop, tags that needed to use the currentLabel would call a VelociMacro called nestedBindTo.  This would prepend the currentLabel to the property name and place it in the bindTo attribute.

   Here's the problem I'm trying to solve.  The controller's model has a List of something, say of Object Group. Each Group wants to be a Panel or Accordion or table row.  Each Group has a List of Items.  These want to be in a table or ordered/unorder list.  They want to be able to subscribTo or reRenderOn events, so they need to be bound back to the controller's Model by the JavaScript engine.  The end rendered result would look like this:  

<ul id="groups" subscribeTo="save" bindTo="groups">
   <ul subscribeTo="save" bindTo="groups.0">
      <li><input type="text" subscribeTo="save" bindTo="groups.0.item.0" value="Exciting Item One"></li>
      <li><input type="text" subscribeTo="save" bindTo="groups.0.item.1" value="Boring Item Two"></li>
   </ul>
   <ul subscribeTo="save" bindTo="groups.1">
      <li><input type="text" subscribeTo="save" bindTo="groups.1.item.0" value="Group 2 Item One"></li>
      <li><input type="text" subscribeTo="save" bindTo="groups.1.item.1" value="Group 2 Item Two"></li>
   </ul>
</ul>  

   I could finish my class hack on the foreach Directive, but this is a terrible hack and very fragile.  Another option would be to dump the responsibility for nesting on Devlopers.  This puts a load of tedious mapping on the Developer and is error prone.  I would still provide the currentLabel, scope stack, and nestedBindTo VelociMacro as well as push and popAndSetCurrentLabel methods for the stack.  Coding would have to look like this:  

#set( $currentLabel = 'groups' )
<ul id="groups" subscribeTo="save" data="#bindTo( 'groups' )">
#foreach( $group in $page.groups )
#push( $currentLabel )
#set( $currentLabel = $currentLabel'.'$foreach.index )
   <ul subscribeTo="save" data="#nestedBindTo( $currentLabel )">
   #foreach( $item in $group )
      #push( $currentLabel )
      #set( $currentLabel = $currentLabel'.'$foreach.index )
      <li><input type="text" subscribeTo="save" value="#nestedBindTo( $currentLabel )"></li>
      #popAndSetCurrentLabel()
   #end
   #popAndSetCurrentLabel()
#end  

   This points out a number of flaws in the design.  It does not handle non-form elements having a binding where the value gets displayed.  As an example, what if the list items above want to have their values displayed as simple text?

<li data="#nestedBindTo( $currentLabel )"> --- How to get and show the value here? How will it be reRendered? --</li>

This wants a completely different solution.

No comments:

Post a Comment