Yeah that looks like exactly what I'm looking for.

I'm just debating the two options: 1. Use many snippets and pass the
current item down through a request var.  2. Use one snippet (composed
of many internal function calls) and pass the current item down as a
parameter.

I'll give both a shot, thanks for your help.  Intuitively I seem to be
leaning towards #1 I think for the same reason I don't normally use
just one snippet call per xhtml page, instead I make several smaller
snippet calls for each page.

I appreciate all the ideas and advice.

- Alex

On Dec 23, 10:22 pm, Ross Mellgren <dri...@gmail.com> wrote:
> I guess I could see something that keeps track of which item to show and 
> advances it each time, but I think it's still a good idea to pass the item 
> explicitly down to subsidiary "snippets". You can still break up each of the 
> sub snippets, the only difference is you call them without the lift: prefix. 
> This is analogous to composing functions.
>
> Maybe something like this?
>
> object MySnippet {
>     object nextItems extends RequestVar[Iterator[ModelObject]](calcNextItems)
>
>     def nextItem: Box[ModelObject] = {
>         val it = nextItems.is
>         if (it.hasNext) Full(it.next) else Empty
>     }
>
>     private def calcNextItems: List[ModelObject] =
>         for (startIndex <- S.attr("index").flatMap(asInt).openOr 0)
>             yield ModelObject.findAll(StartAt(startIndex), 
> MaxRows(2)).elements
>
> }
>
> class MySnippet extends DispatchSnippet {
>     import MySnippet._
>
>     val dispatch: DispatchIt = {
>         case "displayNext" => displayNextItem
>     }
>
>     def displayNext(ns: NodeSeq): NodeSeq) =
>         nextItem.map(renderItem(ns) _).openOr(NodeSeq.Empty)
>
>     def renderItem(item: ModelObject)(ns: NodeSeq): NodeSeq =
>         bind("item", ns, "which" -> item.title,
>              "points" -> renderPointsOf(item) _,
>              // other "sub" snippet which need a current item here
>              "picture" -> renderPictureOf(item) _)
>
>     def renderPointsOf(item: ModelObject)(ns: NodeSeq): NodeSeq =
>         item.points.flatMap(point => bind("point", ns, "name" -> point.name))
>
>     def renderPictureOf(item: ModelObject)(ns: NodeSeq): NodeSeq =
>         <img src={ ... } />
>
> }
>
> And template item-index-2up.html:
>
> <h1>Items</h1>
>
> <lift:Item.displayNext eager_eval="true">
>     <lift:embed what="standard-item-template" />
> </lift:Item.displayNext>
> <lift:Item.displayNext eager_eval="true">
>     <lift:embed what="standard-item-template" />
> </lift:Item.displayNext>
>
> templates-hidden/standard-item-template.html:
>
> <h2><item:which /></h2>
>
> <ul>
>     <item:points><li><point:name /></li></item:points>
> </ul>
>
> <item:picture />
>
> I fear I'm not quite understanding what you're looking for, though.
>
> -Ross
>
> On Dec 23, 2009, at 9:43 PM,AlexBlackwrote:
>
>
>
> > 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 <dri...@gmail.com> 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,AlexBlackwrote:
>
> >>> 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,AlexBlackwrote:
>
> >>>>> 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
>
> ...
>
> read more »

--

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