So, with nested snippets you have two basic execution model options:

   1) the default, the inner snippets get executed after the outer  
snippet has executed completely. the outer snippet sees as it's  
content the original content from the template, complete with  
lift:Item.points tags and so on.
   2) when eager_eval="true" is specified on the outer snippet, the  
inner snippets get executed completely before the outer snippet gets  
executed. the outer snippet sees the _result_ of processing the  
children from the template, so it sees whatever the lift:Item.points  
snippet gives back.

So, this means that fundamentally you couldn't tell the inner snippet  
which is the current one, without rewriting the call to the inner  
snippet (e.g. find the <lift:Item.points> tag and write in an  
attribute -- this seems like a grody hack)

If you really want an inner snippet running _during_ the processing of  
the outer snippet, I think you need to do that  
processSurroundAndInclude thing in the outer snippet code.

If you're not tied to the inner snippet, then omit it, like this:

class Item extends DispatchSnippet {
     val dispatch: DispatchIt = {
         case "firstAndSecond" => firstAndSecond
     }

     def firstAndSecond(ns: NodeSeq): NodeSeq =
         List(("first", firstSeqOfThings), ("second",  
secondSeqOfThings)).flatMap {
             case (label, items) =>
                 bind("item", ns,
                      "which" -> label,
                      "points" -> { (ns: NodeSeq) => items.flatMap  
{ item =>
                          bind("point", ns, "name" -> item.name)
                      })
         }
}

And the template would be:

<h1>Items</h1>

<lift:Item.firstAndSecond>
     <h2><item:which /></h2>
     <ul>
         <item:points>
             <li><point:name /></li>
         </item:points>
     </ul>
     <item:picture />
</lift:Item.firstAndSecond>

If you're concerned about embedding so much code in the snippet (which  
seems to be why you want to break into multiple snippets?) then just  
break them out into separate functions, like I showed you in the  
foreach example.

I think it helps to remember that snippets are really just XML -> XML  
functions, and there's little special about them other than that they  
can be named in templates. You can always call snippets from other  
snippets directly (e.g. (new MySnippet).thatSnippet(nodes)), though if  
you use any stateful stuff in those snippets that depends on the  
current expansion point (e.g. S.attr) then you'd need to break the  
snippet into two pieces, e.g.

class MySnippet extends DispatchSnippet {
     val dispatch: DispatchIt = {
         case "foobar" => foobar
     }

     def foobar(ns: NodeSeq): NodeSeq = {
         S.attr("itemId").map(lookupItemById _) match {
             case Full(item) => foobar(item)(ns)
             case _ => error("could not find item -- itemId attribute  
not given or invalid")
         }
     }

     def foobar(item: ItemModel)(ns: NodeSeq): NodeSeq =
         bind(...)
}

Now if you're calling from template, you say <lift:MySnippet.foobar  
itemId="1234">...</lift:MySnippet.foobar>, but if you're in some other  
snippet you say MySnippet.foobar(theItem)(...)

Hope that helps,
-Ross



On Dec 23, 2009, at 4:32 PM, Alex Black wrote:

> Thanks Ross, I think I get that.. I'm not seeing the full picture yet,
> let me show a bit more of my thinking:
>
> So, extending my previous example, I'd like to write it like this:
>
> <h1>Items</h1>
>
> <lift:Item.firstAndSecond>
> <h2><item:which></h2>
> <ul>
>  <lift:Item.points>
>    <li><point:name />
>  </lift:Item.points>
> </ul>
> <lift:item.picture />
> </lift:Item.firstAndSecond>
>
> // Emit the block twice, once for each item (first,second).
> def firstAndSecond(xhtml: NodeSeq): NodeSeq = {
>  List(first,second).flatMap( item => renderItem(xhtml, item) )
> }
>
> How then do I implement Item.picture, Item.points to know *which* item
> is currently being rendered?
>
> thx
>
> - Alex
>
>
>
>
>
>
> On Dec 23, 4:18 pm, Ross Mellgren <dri...@gmail.com> wrote:
>> S.attr gives you attributes of the current snippet calling tag, e.g.
>>
>> class Item extends DispatchSnippet {
>>      val dispatch: DispatchIt = {
>>          case "points" => points
>>      }
>>
>>      def points(ns: NodeSeq): NodeSeq = {
>>          val points = S.attr("item") match {
>>              case Full("first") => loadFirstListOfPoints()
>>              case Full("second") => loadSecondListOfPoints()
>>              case _ => error("missing item attribute or has incorrect
>> value")
>>          }
>>
>>          bind(...)
>>      }
>>
>> }
>>
>> -Ross
>>
>> On Dec 23, 2009, at 4:07 PM, Alex Black wrote:
>>
>>> I've got some xhtml blocks in one of my templates that are basically
>>> identical, and I'd like to avoid the duplication, by either writing
>>> the block once in my template and using a snippet to write it out
>>> twice (with different values) or put it in its own template.
>>
>>> <h1>Items</h1>
>>
>>> <h2>First</h2>
>>> <ul>
>>>  <lift:Item.firstPoints>
>>>    <li><point:name />
>>>  </lift:Item.firstPoints>
>>> </ul>
>>> <lift:item.firstPicture />
>>
>>> <h2>Second</h2>
>>> <ul>
>>>  <lift:Item.secondPoints>
>>>    <li><point:name />
>>>  </lift:Item.secondPoints>
>>> </ul>
>>> <lift:item.secondPicture />
>>
>>> My question is: If I write this block once, and surround it in a
>>> snippet which emits it twice, how can the snippet parameterize the
>>> nested snippet calls?
>>
>>> I realize I could bind the entire block with one snippet call, but
>>> because my real blocks are big and complex I'd like to keep the many
>>> snippet calls per block.
>>
>>> So, more specifically, how can i write <lift:Item.secondPoints> and
>>> <lift:item.firstPoints> more like this: <lift:item.points
>>> item="@curItem">
>>
>>> thx
>>
>>> - Alex
>>
>>> --
>>
>>> You received this message because you are subscribed to the Google
>>> Groups "Lift" group.
>>> To post to this group, send email to lift...@googlegroups.com.
>>> To unsubscribe from this group, send email to 
>>> liftweb+unsubscr...@googlegroups.com
>>> .
>>> For more options, visit this group 
>>> athttp://groups.google.com/group/liftweb?hl=en
>>> .
>
> --
>
> You received this message because you are subscribed to the Google  
> Groups "Lift" group.
> To post to this group, send email to lift...@googlegroups.com.
> To unsubscribe from this group, send email to 
> liftweb+unsubscr...@googlegroups.com 
> .
> For more options, visit this group at 
> http://groups.google.com/group/liftweb?hl=en 
> .
>
>

--

You received this message because you are subscribed to the Google Groups 
"Lift" group.
To post to this group, send email to lift...@googlegroups.com.
To unsubscribe from this group, send email to 
liftweb+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en.


Reply via email to