Hi, Chas,
Sorry it's taken me so long to respond to this - I've been pretty buried for
the past week.
Here's an example of what I'm doing:
trait Binding {
def apply(xhtml : NodeSeq) : NodeSeq = xhtml
}
trait EntityBinding[+T] extends Binding {
def entity : T
}
trait SubscriptionEventBinding extends EntityBinding[SubscriptionEvent] {
abstract override def apply(xhtml : NodeSeq) : NodeSeq = {
val transTemplate = chooseTemplate("event", "transactions", xhtml)
bind("event", super.apply(xhtml),
"scheduleDate" -> h(entity.getScheduleDate),
"transactions" ->
Group(entity.getTransactions.toSeq.flatMap(_(transTemplate)))
)
}
}
trait BillingEventBinding extends EntityBinding[SubscriptionBillingEvent]
with SubscriptionEventBinding {
abstract override def apply(xhtml : NodeSeq) : NodeSeq = {
bind("event", super.apply(xhtml),
"detail" -> <span>Charges: ${entity.getCharge}; Discount:
${entity.getDiscount}</span>,
"type" -> h("Billing"))
}
}
trait CancellationEventBinding extends
EntityBinding[SubscriptionCancellationEvent] with SubscriptionEventBinding {
abstract override def apply(xhtml : NodeSeq) : NodeSeq = {
bind("event", super.apply(xhtml),
"detail" -> <div>Reason: {entity.getReason}<br/>Final Balance:
{entity.getFinalBalance}</div>,
"type" -> h("Cancellation"))
}
}
Then, in the appropriate scope, I import the correct implicit:
implicit def entityToEventBinding(e : SubscriptionEvent) : Binding = {
e match {
case b : SubscriptionBillingEvent => new
BillingEventBinding { override val entity = b }
case c : SubscriptionCancellationEvent => new
CancellationEventBinding { override val entity = c }
case _ => throw new IllegalStateException("Unbindable event " +
e.getClass + " (" + e + ")")
}
}
All of the entity classes are JPA entities implemented in Java. If I have a
different set of bindings for a different context, I simply create a
separate trait. The nice thing about this approach is that the traits are
stackable over an inheritance hierarchy, as above.
With this in place, I can just treat my entity as a binding context on its
own:
object Subscriptions {
object current extends SessionVar[Box[Subscription]](Empty)
}
... stuff that populates the SessionVar
def events(xhtml : NodeSeq) : NodeSeq = {
Subscriptions.current.is.map(_.events.toSeq.flatMap(_(xhtml))).openOr(h("No
subscription to display events for."))
}
Kris
On Fri, Jan 9, 2009 at 5:29 PM, Charles F. Munat <[email protected]> wrote:
>
> That sounds kinda smart. Is there any chance you could post some example
> code?
>
> Chas.
>
> Kris Nuttycombe wrote:
> > Oh, I'm not complaining about the way User is handled - my response was
> > more about the general hate towards MVC upthread. Having a sensible
> > default for a standard use case is great, even when I'll probably never
> > use the default.
> >
> > In my Lift app, my shortcut to different renderings (well, different
> > bindings, really) is to keep all the binding logic for a specific case
> > in a trait and have an implicit conversion from my model to the
> > appropriate trait in the relevant scope. You still have to do the work,
> > but it makes the bindings a lot easier to reuse.
> >
> > Kris
> >
> > On Fri, Jan 9, 2009 at 4:46 PM, Charles F. Munat <[email protected]
> > <mailto:[email protected]>> wrote:
> >
> >
> > I don't see how you're any worse off if the model can render itself
> in
> > one way. And if that way is a common standards-compliant way, such as
> > rendering to XML, and you include semantic information, then you can
> > layer any other layers you want on top to do the mapping to the 30
> > different contexts.
> >
> > Saying that an object should know how to render itself to some
> > universally recognized format is not the same as saying that that
> solves
> > all rendering issues.
> >
> > Is there some shortcut to 30 different renderings that I'm missing,
> or
> > do you have to do the work either way?
> >
> > Chas.
> >
> > Kris Nuttycombe wrote:
> > > If you want to render a model 30 different ways in 30 different
> > > contexts, it kind of sucks though, doesn't it?
> > >
> > > Or what if, shock horror, you don't know how the eventual system
> is
> > > going to want to render the model (i.e., the person doing the
> > rendering
> > > won't be able to change the model code.) Not too uncommon, I
> > don't think...
> > >
> > > Kris
> > >
> > > On Sun, Jan 4, 2009 at 9:58 AM, Michael <mike.sr <http://mike.sr>
> > > <http://mike.sr>@gmail.com <http://gmail.com> <http://gmail.com>>
> > wrote:
> > >
> > >
> > > > Also I was looking at the sample model source code (User,
> > ProtoUser)
> > > > and saw presentation logic mixed in it. Shouldn't the
> > business and
> > > > model logic be kept separated from the presentation logic
> > or is there
> > > > a Lift strategy it?
> > >
> > > Hmm, a model that can render itself ... That sounds like this
> > crazy
> > > paradigm called object-oriented programming. Some radicals
> > say it has
> > > some advantages over the more procedural style of MVC.
> > >
> > > -- Michael
> > >
> > >
> > >
> > >
> > > >
> >
> >
> >
> >
> > >
>
> >
>
--~--~---------~--~----~------------~-------~--~----~
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
-~----------~----~----~----~------~----~------~--~---