Journey to a better radio

77 views
Skip to first unread message

Matt Farmer

unread,
Oct 12, 2015, 5:46:15 PM10/12/15
to Lift
Hey folks,

I wanted to call your attention to a branch I just pushed with this commit in it: https://github.com/lift/framework/commit/03349f43c03fb863f36670bb32110e02f0f5b32d

At Elemica we’ve run into a lot of situations in the past several months where Lift’s standard radio handling yields incredibly undesirable behavior. The wholesale replacement of elements on the page means that if we’ve applied any meaningful attributes to them we have to make sure those are mirrored in the Scala invocation of radio* (e.g. the id of the radio that a label tag may depend on) and the hidden fields that the default Lift handling injects for radios causes styles in CSS that depend on ordering (e.g. “input[type=radio] + label” or “the label immediately after a radio button”) to not behave as we’d expect them to.

The radioCssSel method introduced in that commit provides a solution to these problems.

By binding the radio button using CSS selectors, we leave unaltered attributes (e.g. id and class) left alone. We only set the name, the value, and the checked attributes on the input nodes. Radios are associated using CSS selectors instead of needing to reference the index of a ChoiceHolder to get at the exact radio button instance.

So, let’s take this example to illustrate what I’m talking about:

<label for=“name”>
<input type=“text” id=“name”>

<input type=“radio” id=“get-all-emails”>
<label for=“get-all-emails”>

<input type=“radio” id=“get-no-emails”>
<label for=“get-no-emails”>

This is a simple form set up with some best practices. Here, every field is labeled and (thanks to the for attribute in label) you cal click the label in the browser to actually select the associated input. They’re linked by the id of the input. This is a huge usability win because that makes the clickable area for selecting a radio button more than just the circle of the radio. It’s easier to hit.

So, with my new radioCssSel code you could write:

“#name” #> text(name, name = _) &
radioCssSel[Boolean](Full(true), emailSelection = _) {
  “#get-all-emails” -> true,
  “#get-no-emails” -> false
}

And it would continue to behave as the original author of the HTML intended. By contrast, if you were to attempt to do this using the current radioElem method you’d have to do something like:

val radios = radioElem[Boolean](
  true :: false :: Nil, 
  Full(true)
)(emailSelection = _)

“#name” #> text(name, name = _) &
“#get-all-emails” #> radios(0) % “id” -> “get-all-emails” & //preserve ID
“#get-no-emails” #> radios(1) % “id” -> “get-no-emails”

This radioElem has a few disadvantages:

  1. We’ve got to duplicate the ID in scalaland to preserve it so the labels continue to function correctly. Not to mention any css classes or anything else that might also be applied.
  2. This will result in the insertion of hidden input fields between the radios and the labels which will mean that styles based on position won’t work as intended.
  3. The values are separated farther away from what their bound to. Using the radioCssSel method it’s clear that #get-all-emails is the true radio. Using radioElem it’s not quite as clear. Perhaps when you only have two values the difference is minimal, but if you scale up to more than 2 radios it can quickly become cumbersome to try and figure out which radio causes what value to be populated.

I’d like to propose we include radioCssSel in Lift 3, and perhaps we start thinking about replacing radioElem wholesale in a future release of Lift. Also, a hat tips go to Antonio Salazar Cardozo who I believe contributed the original ideas around how this could work and Piotr Dyraga for making some contributions to this code structure as well. (And if I forgot someone else on the Elemica team who helped then please accept my apologies.)

Would love thoughts and comments on this.

Cheers,


Matt Farmer Blog | Twitter

Antonio Salazar Cardozo

unread,
Oct 15, 2015, 1:32:45 PM10/15/15
to Lift
I diiig it!

Matt Farmer

unread,
Oct 21, 2015, 7:26:58 PM10/21/15
to Lift
FYI everyone: Opened a PR here.


Matt Farmer Blog | Twitter
GPG: CD57 2E26 F60C 0A61 E6D8  FC72 4493 8917 D667 4D07

--
--
Lift, the simply functional web framework: http://liftweb.net
Code: http://github.com/lift
Discussion: http://groups.google.com/group/liftweb
Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code

---
You received this message because you are subscribed to the Google Groups "Lift" group.
To unsubscribe from this group and stop receiving emails from it, send an email to liftweb+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Joe Barnes

unread,
Oct 24, 2015, 3:29:01 PM10/24/15
to Lift
I have it on my list to check this out this weekend.  But for now, time to watch the Tide roll over the Vols.

Joe

Joe Barnes

unread,
Oct 25, 2015, 10:01:08 PM10/25/15
to Lift
Got it. Looks great! My only changes are for the code example.

Joe
Reply all
Reply to author
Forward
0 new messages