Hi Ross, I am learning more about Lift every day :)

Reflecting that last point back to you, if I make it just one snippet
call, then that snippet call can pass parameters to inner snippet
functions, e.g. first or second.

So, that works, but I as you mentioned, I think that snippet will get
complex.  You then pointed out it can be broken into sub snippet
calls, which helps, but I still feel like we'd have this big complex
snippet call that is tightly coupled to the big complex xhtml block.
E.g. it'd be like doing an entire page in one snippet call instead of
lots of little ones.

Btw, the 'blocks' I keep referring to are product (camera)
specifications, so its like we're displaying two products on one page.

I had an idea, could the first snippet set a requestVar for the
current item, then the other snippet calls read that? e.g.

<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) )
}

def renderItem( xhtml: NodeSeq, item: Item): NodeSeq = {
  _currentItem(item)
   // do stuff
}

def points( xhtml: NodeSeq ): NodeSeq = {
   // do stuff based on _currentItem.is
}

- Alex

On Dec 23, 5:05 pm, Ross Mellgren <[email protected]> wrote:
> 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 <[email protected]> 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 [email protected].
> >>> To unsubscribe from this group, send email to 
> >>> [email protected]
> >>> .
> >>> 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 [email protected].
> > To unsubscribe from this group, send email to 
> > [email protected]
> > .
> > 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 [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/liftweb?hl=en.


Reply via email to