Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala / Lift - Trying to understand Lift's simultaneous claim to use valid html and propensity for lift: tags and tag rewriting in render

All of the Seven Things (http://seventhings.liftweb.net/) are certainly nice, but I was particularly enthusiastic about the claim in Templates (http://seventhings.liftweb.net/templates) that "Lift supports designer friendly templates."

As one of my steps in learning Lift's way of doing things I'm attempting to create a simple object creation form: take a few parameters, use them as constructor arguments, then stow the object away. After some research and experimentation, tho, I have two concerns:

  1. There seems to be a considerable propensity for significantly rewriting/embellishing the template markup in snippets.
  2. Forms don't seem to use valid or recognizable html elements.

What I'm basing this on:

The form examples/documentation seems all about special lift: tags. Exploring Lift suggests that a form should look like this: (http://exploring.liftweb.net/master/index-6.html)

<lift:Ledger.add form="POST">
  <entry:description />
  <entry:amount /><br />
  <entry:submit />
</lift:Ledger.add>

I'm not sure that's even valid html5 and while it might be valid xhtml, it doesn't feel like that meets the spirit of having your templates look like real html for our designer friends. I read somewhere else (can't find it again) that we did have the option of using actual input tags, but then we wouldn't get some parts of Lift's fancy form wire-up or somesuch, the passage wasn't very clear on what exactly I'd be missing out and the examples don't seem interested in my writing a plain html form making a plain html post.

The code for a demo.liftweb.net example (1) suggests that your template should look like this (2)

<lift:surround with="default" at="content">
  <div class="lift:PersonScreen"></div>
</lift:surround>

The code for PersonScreen snippet isn't exactly illuminating, either (3). There are several other examples of a template that has, e.g. only a ul tag in a particular location only to generate a whole series of complex li's with nested elements in the snippet. Sure, you can use xml in Scala and it reads tolerably, but it's still scattering your markup everywhere. This seems to violate the spirit of "designer friendly templates".

What I want to understand.

For a long time I've strictly followed two rules in my webapp development:

  1. No markup in 'code' (controllers, business models).
  2. No business logic in the templates whatsoever.

Idiomatic Lift seems to completely forego the first rule and completely miss the value of the second rule. These rules have served me well and I'm not ready to just follow along with the examples that seem to be violating them without understanding why its not going to create a mess. I want to understand why it's okay in Lift to have so much display code generated in the Snippets. I also want to understand why its okay that the markup in the templates so rarely reflects the output.

What I (think I) want:

I want all of my markup with very few, if any, exceptions to be in my templates. I want my snippets to do minimal template mangling, generally only replacing element text on "leaf" tags and possibly tweaking attribute values. I think I've done this for a reasonably complex display example and I suspect I could use the same technique to generate a vanilla html form and then handle the params myself. Is that what I need to do if I want my template to look like the end-result form?

Responses and any other thoughts, especially on understand the Lift mindset regarding this stuff, would be tremendously appreciated.

Thanks!

  1. http://demo.liftweb.net/simple_screen?F674431078927QJVVYD=_
  2. https://github.com/lift/examples/blob/master/combo/example/src/main/webapp/simple_screen.html
  3. https://github.com/lift/examples/blob/master/combo/example/src/main/scala/net/liftweb/example/snippet/Wizard.scala#L94

EDIT

In response to @OXMO456. (Thanks for the response.)

I have, and they seem to just confirm my concerns: E.g. we start with:

Lift templates contain no executable code. They are pure, raw, valid HTML.

which is awesome. Then later:

The latter two mechanisms for invoking snippets will not result in valid Html5 templates.

and yet everyone seems to use the first of those two mechanisms. Also, it says:

Third, the designers don’t have to worry about learning to program anything in order to design HTML pages because the program execution is abstracted away from the HTML rather than embedded in the HTML.

But pretty consistently the example snippets like the one I referenced in the OP generate markup entirely programmatically. This seems counter to the goals (a) of having designer friendly templates so the designers don't have to be bothered with Freemarker markup and (b) separating display logic from business logic.

The second link is helpful and instructive, but it makes it pretty clear that this isn't The Lift Way. However, The Lift Way also seems to drag a whole load of markup generation into snippets, which is (I think) a huge compounding of markup and business logic. Is that The Lift Way?

like image 550
Najati Avatar asked Jun 22 '11 19:06

Najati


2 Answers

Those are old-style tags, not designer-friendly tags.

<lift:MySnippet>
  <b:field />
</lift:MySnippet>

becomes

<div class="lift:MySnippet">
  <div class="field"></div>
</div>

Old-style Lift templates are valid XML, not XHTML - so you can't have unclosed tags or anything - this differentiates Lift from most frameworks, which treat templates as raw strings with bits of code intertwined throughout, without regard to tags or structure.

BTW, in old-style tags, those fields are all fabricated - they aren't part of some standard set of Lift tags. I could just as easily do:

<lift:MySnippet>
  <frobnicate:blorb />
</lift:MySnippet>

as long as my snippet code is looking for that specific tag.

Lift doesn't allow any logic in your templates. All of the logic happens in your Snippet class. So for the designer-friendly example above, I might have a snippet class like this:

 class MySnippet { 
   def render(in: NodeSeq): NodeSeq = ".field" #> Text("some text here")
 }

which would yield this result:

 <div>
   <div class="field">some text here</div>
 </div>

It's impossible to put any logic in Lift templates - all they can do is invoke Lift snippets, which are regular Scala classes where all of the work happens.

Lift discards the rule that you shouldn't have any display logic in your real code. Why? Because it makes for more reusable code, because Scala has powerful XML support baked into the language and because all of your logic is now treated as plain old Scala code.

If I define a Lift snippet called CurrentTime, I can simply drop that in to any template and it will display the current time - with old-school MVC frameworks, each action method needs to set the time as a page variable and then my templates would need to be modified to print it out. For more complicated logic, old-school frameworks would probably require a conditional in the templates. Lift doesn't allow that - all of your logic is regular Scala code, eligible for refactoring, easily testable, and compatible with modern IDE's.

like image 135
Bill Avatar answered Nov 09 '22 18:11

Bill


In answer to you're "what I think I want" question, sure you can do that no problem. Lift is really all about choices, and understanding your use case. Often the samples you see with Lift intermingle code and markup, which is of course sub-optiomal. The important thing to note is that snippets conceptually are solely designed to produce markup, and render the view.

In addition, as Lift follows its view first paradigm the only thing that the view actually requires is a notation to outline which sections of markup you want to process in which rendering snippets. There are several ways, as illustrate by both the OP and "Bill", but personally I prefer:

<div lift="YourSnippet.method">
  <p>Some other code</p>
</div>

This is preferable because you're then not culturing up the class attribute which (IMO) can be confusing for designers. Lift can be very designer friendly, but I think the main problem here is that you have to be both disciplined when writing your snippets whilst ignoring many of the samples available today which mix Scala and markup.

You may also be interested in this post ( http://blog.getintheloop.eu/2011/04/11/using-type-classes-for-lift-snippet-binding/ ); using this sort of pattern you can define decoupled, reusable parts of rendering logic whilst keeping your business logic safely out of the snippets.

Finally, and without wanting to shamelessly promote my own product, but I specifically went out of my way to not use any mixed Scala xml literals in my example code for Lift in Action (other than to illustrate that its possible), so perhaps it might be of assistance if you're looking at Lift ( http://manning.com/perrett/ )

like image 26
timothy Avatar answered Nov 09 '22 20:11

timothy