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
-~----------~----~----~----~------~----~------~--~---

Reply via email to