Wiring, the most powerful feature in Lift (or any other web framework), ever

222 views
Skip to first unread message

David Pollak

unread,
Dec 2, 2010, 2:56:37 AM12/2/10
to liftweb
Folks,

I've got Spreadsheets in my veins and I can't seem to get them out (I guess that's what happens when you've written 3 commercial spreadsheets, one is still available today http://www.plsys.co.uk/mesa.htm)

I've added a new feature to Lift (it'll be on review board tomorrow, but you can see it in action right now).  The feature is called wiring.  You can wire together a relationship of things.  For example, a list of invoice lines, subtotals, taxable totals, tax rates, etc:
case class Line(guid: String, name: String, price: Double, taxable: Boolean)

private object Info {
val invoices = ValueCell(List(newLine))
val taxRate = ValueCell(0.05d)
val subtotal = invoices.lift(_.foldLeft(0d)(_ + _.price))
val taxable = invoices.lift(_.filter(_.taxable).
foldLeft(0D)(_ + _.price))

val tax = taxRate.lift(taxable) {_ * _}

val total = subtotal.lift(tax) {_ + _}
}
Next, you can specify snippets to display these items:

  def subtotal(in: NodeSeq) = WiringUI.asText(in, Info.subtotal)

def taxable(in: NodeSeq) = WiringUI.asText(in, Info.taxable)

def tax(in: NodeSeq) = WiringUI.asText(in, Info.tax, JqWiringSupport.fade)

def total(in: NodeSeq) = WiringUI.asText(in, Info.total, JqWiringSupport.fade)

And finally, you update your view to invoke the snippets:

  <div>Subtotal: <span class="lift:InvoiceWiring.subtotal">subtotal</span></div>

<div>Tax Rate: <input class="lift:InvoiceWiring.taxRate"></div>

<div>Taxable: <span class="lift:InvoiceWiring.taxable">taxable</span></div>

<div>Tax: <span class="lift:InvoiceWiring.tax">Tax</span></div>

<div>Total: <span class="lift:InvoiceWiring.total">Total</span></div>

When the values of the cells (e.g. invoices) changes, the other cells are recalculated and the page is updated automatically.  This differs from Comet in that (1) the components are page-specific (2) the update occurs on as part of another HTTP response (typically part of the Ajax response, although it could be part of the Comet response) but is not "pushed" if there's no pending HTTP request and (3) the real estate is much more granular than the Comet real estate.

You can play with examples of the code at http://demo.liftweb.net/invoice_wiring and http://demo.liftweb.net/simple_wiring

Wiring will make it super-simple to define relationships among components on the page and automatically update those components based on user actions.

I'll write up more documentation over the weekend.

Thanks,

David

--
Lift, the simply functional web framework http://liftweb.net
Beginning Scala http://www.apress.com/book/view/1430219890
Follow me: http://twitter.com/dpp
Blog: http://goodstuff.im
Surf the harmonics

Heiko Seeberger

unread,
Dec 2, 2010, 3:24:43 AM12/2/10
to lif...@googlegroups.com
David,

Looks very interesting!
Can't wait to see it in master ...

Heiko

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



--
Heiko Seeberger

Company: weiglewilczek.com
Blog: heikoseeberger.name
Follow me: twitter.com/hseeberger
OSGi on Scala: scalamodules.org
Lift, the simply functional web framework: liftweb.net
Akka - Simpler Scalability, Fault-Tolerance, Concurrency & Remoting through Actors: akkasource.org

Indrajit Raychaudhuri

unread,
Dec 2, 2010, 3:44:16 AM12/2/10
to lif...@googlegroups.com
The construct looks quite powerful indeed!

- Indrajit

Heiko Seeberger wrote:
> David,
>
> Looks very interesting!
> Can't wait to see it in master ...
>
> Heiko
>
> On 2 December 2010 08:56, David Pollak <feeder.of...@gmail.com

> <mailto:feeder.of...@gmail.com>> wrote:
>
> Folks,
>
> I've got Spreadsheets in my veins and I can't seem to get them out
> (I guess that's what happens when you've written 3 commercial
> spreadsheets, one is still available today
> http://www.plsys.co.uk/mesa.htm)
>
> I've added a new feature to Lift (it'll be on review board tomorrow,
> but you can see it in action right now). The feature is called
> wiring. You can wire together a relationship of things. For
> example, a list of invoice lines, subtotals, taxable totals, tax
> rates, etc:
>

> case class Line(guid:String,name:String,price:Double,taxable:Boolean)

> <mailto:lif...@googlegroups.com>.


> To unsubscribe from this group, send email to
> liftweb+u...@googlegroups.com

> <mailto:liftweb%2Bunsu...@googlegroups.com>.


> For more options, visit this group at
> http://groups.google.com/group/liftweb?hl=en.
>
>
>
>
> --
> Heiko Seeberger
>

> Company: weiglewilczek.com <http://weiglewilczek.com>
> Blog: heikoseeberger.name <http://heikoseeberger.name>
> Follow me: twitter.com/hseeberger <http://twitter.com/hseeberger>
> OSGi on Scala: scalamodules.org <http://scalamodules.org>
> Lift, the simply functional web framework: liftweb.net <http://liftweb.net>


> Akka - Simpler Scalability, Fault-Tolerance, Concurrency & Remoting

> through Actors: akkasource.org <http://akkasource.org>

Mads Hartmann Jensen

unread,
Dec 2, 2010, 3:44:52 AM12/2/10
to lif...@googlegroups.com
Looks very cool. Looking forward to the docs :)

Mads

philip

unread,
Dec 2, 2010, 3:50:38 AM12/2/10
to Lift
Hi David,

It seems like value binding with event notification? Maybe the Scala
Sgine game engine does something similar http://www.sgine.org/

Philip

On Dec 2, 3:56 pm, David Pollak <feeder.of.the.be...@gmail.com> wrote:
> Folks,
>
> I've got Spreadsheets in my veins and I can't seem to get them out (I guess
> that's what happens when you've written 3 commercial spreadsheets, one is
> still available todayhttp://www.plsys.co.uk/mesa.htm)
> You can play with examples of the code athttp://demo.liftweb.net/invoice_wiringandhttp://demo.liftweb.net/simple_wiring
>
> Wiring will make it super-simple to define relationships among components on
> the page and automatically update those components based on user actions.
>
> I'll write up more documentation over the weekend.
>
> Thanks,
>
> David
>
> --
> Lift, the simply functional web frameworkhttp://liftweb.net
> Beginning Scalahttp://www.apress.com/book/view/1430219890

Timothy Perrett

unread,
Dec 2, 2010, 4:10:56 AM12/2/10
to Lift
David,

Great feature; this no doubt has some great application use cases.

Cheers, Tim

On Dec 2, 7:56 am, David Pollak <feeder.of.the.be...@gmail.com> wrote:
> Folks,
>
> I've got Spreadsheets in my veins and I can't seem to get them out (I guess
> that's what happens when you've written 3 commercial spreadsheets, one is
> still available todayhttp://www.plsys.co.uk/mesa.htm)
> You can play with examples of the code athttp://demo.liftweb.net/invoice_wiringandhttp://demo.liftweb.net/simple_wiring
>
> Wiring will make it super-simple to define relationships among components on
> the page and automatically update those components based on user actions.
>
> I'll write up more documentation over the weekend.
>
> Thanks,
>
> David
>
> --
> Lift, the simply functional web frameworkhttp://liftweb.net
> Beginning Scalahttp://www.apress.com/book/view/1430219890

David Brooks

unread,
Dec 2, 2010, 5:30:25 AM12/2/10
to lif...@googlegroups.com

On 2 Dec 2010, at 07:56, David Pollak wrote:

> I've added a new feature to Lift (it'll be on review board tomorrow, but you
> can see it in action right now). The feature is called wiring. You can
> wire together a relationship of things. For example, a list of invoice
> lines, subtotals, taxable totals, tax rates, etc:

Oh yeah!

Reminds me of Flapjax (http://flapjax-lang.org). I'm really looking forward to seeing the details...

Cheers,
D

Naftoli Gugenheim

unread,
Dec 2, 2010, 1:37:03 PM12/2/10
to liftweb
Hey, you took the fun out of my "secret" project!
I hope to be putting up a demo soon G-d willing. It's pretty similar to this in its basic purpose, but it's based on a separate FRP framework and it can deal with incremental updates to transformed sequences.
So you could do
val allPhoneNumbers = for(cs <- contacts) yield cs.flatMap(_.phoneNumbers)
val display: Signal[NodeSeq] = for(ps <- allPhoneNumbers) yield ps.flatMap {phone => <tr><td>{phone}</td></tr> }

The above is possible with the core FRP project at github.com/reactive. The project that I hadn't publicized primarily adds a bunch of html components whose settings are ajax- or comet-updated signals (and events).

I haven't bothered being too detailed because the point of this post is not really to announce it, just to mention that I've been working on something similar but more general.


--

David Pollak

unread,
Dec 2, 2010, 1:43:41 PM12/2/10
to lif...@googlegroups.com
On Thu, Dec 2, 2010 at 10:37 AM, Naftoli Gugenheim <nafto...@gmail.com> wrote:
Hey, you took the fun out of my "secret" project!
I hope to be putting up a demo soon G-d willing. It's pretty similar to this in its basic purpose, but it's based on a separate FRP framework and it can deal with incremental updates to transformed sequences.
So you could do
val allPhoneNumbers = for(cs <- contacts) yield cs.flatMap(_.phoneNumbers)
val display: Signal[NodeSeq] = for(ps <- allPhoneNumbers) yield ps.flatMap {phone => <tr><td>{phone}</td></tr> }

The above is possible with the core FRP project at github.com/reactive. The project that I hadn't publicized primarily adds a bunch of html components whose settings are ajax- or comet-updated signals (and events).

I haven't bothered being too detailed because the point of this post is not really to announce it, just to mention that I've been working on something similar but more general.

The Wiring stuff uses the new LiftSession.addPostPageJavaScript to return a list of JsCmds to return as part of the request for a given page.  It's totally possible for you to hook your FRP framework into the same mechanism so you generate JsCmds (e.g. SetHtml(...)) based on the values in the network.
 

Naftoli Gugenheim

unread,
Dec 2, 2010, 7:13:45 PM12/2/10
to liftweb
Sorry -- I'm not clear. Calling addPostPageJavaScript tells Lift to execute javascript when? Immediately?

David Pollak

unread,
Dec 2, 2010, 11:08:34 PM12/2/10
to lif...@googlegroups.com
On Thu, Dec 2, 2010 at 4:13 PM, Naftoli Gugenheim <nafto...@gmail.com> wrote:
Sorry -- I'm not clear. Calling addPostPageJavaScript tells Lift to execute javascript when? Immediately?

Just before the page is sent to the browser.  And for subsequent requests on the same page (Ajax, Comet), the functions are executed again.  And "same page" means the page rendered based on a full HTTP request, so additional requests to the same URL are not the "same page".
 

Naftoli Gugenheim

unread,
Dec 3, 2010, 12:12:52 PM12/3/10
to liftweb
So what would be a typical use case?

David Pollak

unread,
Dec 3, 2010, 12:38:38 PM12/3/10
to lif...@googlegroups.com
On Fri, Dec 3, 2010 at 9:12 AM, Naftoli Gugenheim <nafto...@gmail.com> wrote:
So what would be a typical use case?

Wiring is the only use case that I know of, but if you wanted to mix your FRP system into Lift, this is the logical place to integrate the two.
 

Naftoli Gugenheim

unread,
Dec 6, 2010, 2:35:34 AM12/6/10
to liftweb
Sorry it's taking me so long to understand, but what am asking is, what specifically does wiring use addPostPageJavaScript for?

In the hopefully-soon-to-be-available reactive-web, I use the following approach. I'm wondering if addPostPageJavaScript is something similar, or nothing to do with this at all.
The library provides signals and events that originate from the browser (currently only via ajax, although "submit" event is planned). Signals and events can also originate from the server of course (e.g., a timer) -- ordinary signals and events.
It also allows one to update the client, either by defining html elements around signals or events (e.g. a <select>'s contents might be contructed with a SeqSignal[Customer]), or by updating mutable properties (selectElem.selectedIndex ()= 3). How does the library actually send the resulting javascript to the client?
The implementation uses a few of its methods: One that queues javascript in whatever the current thread-local context is, one that runs code in a server-side, page-specific context (c.f. doWith, withValue), and one that runs code in a client-side context.
When it runs code in a client-side context, all javascript queued is returned. Handling an ajax event is run in a "client-side" context and any javascript queued for the client is returned from the ajax call.
In order to run server-side javascript, you have to use a special snippet that embeds a unique comet actor in the page. Javascript that is run in a server-side, page-specific context is sent to the comet actor for that page.
Of course the user of the library doesn't have to care about this (other than using the reactive snippet to enable comet-based updates, which is not necessary in many cases).
Reply all
Reply to author
Forward
0 new messages