HowTo create simple controls
From Lift
The S object in scala contains macro methods for the HTML input elements. Additionally there are a lot of useful basic AJAX controls which can be used to build nice pages with good user experience. The next step could be to combine these macros in order to build small but useful controls.
I have started this page with 2 intentions:
- if anyone has a such control to post for others benefit
- to increase the amount of the examples for using lift
Contents |
Filtered Listbox
When we have to display to the user a lot of options from e.g. an options table where there are more than 100 entries, choosing the right one for the user can be painfull. If we would let the user to type in a few letter, the option set would become considerable smaller.
The code of the control
/**
* Builds the XHTML Elem for the filtered listbox
*
* @param sensitivity the sensitivity of the filter. The time after which the list to be refreshed
*
* @param size the size of the listbox. For the value 1; the browser will render a dropdown
*
* @param genFunc the generator function. this function will be called each time the client requests the refresh.
* The String parameter is the text entered so far.
*
* @param selFunc the function to be called when the user selects an elem from the list.
* The String parameter is the key of the selected option.
*
* @return an XHTML elem with the control surround by a div element
*/
def ajaxFilteredList(sensitivity: TimeSpan, size: Int, genFunc: String => List[(String, String)], selFunc: String => JsCmd): Elem = {
val rndID = "S"+System.nanoTime+"_"+randomString(3)
var value = ""
<div><script>var keyTimer;</script>
{text(value, x => {} ) %
("onkeyup" -> ("clearTimeout(keyTimer);keyTimer=" +
After( sensitivity,
Run( ajaxCall("value", (value) =>
ReplaceOptions(rndID, genFunc(value), Empty)
))).toJsCmd ))%
("style" -> "width:100%;")}
{ajaxSelect(genFunc(value), Empty, selected => selFunc(selected) ) %
("size" -> size) % ("style" -> "width:100%;") % ("id" -> rndID)}
</div>
}
Usage
In order to benefit to the control, just call:
ajaxFilteredList( 1.seconds, 10,
filter => Cities.citiesAndStates.filter(_._2 contains filter),
selected => Alert(selected)
) % ("style" -> "width:200px;height:200px;")
(the citiesAndStates map is from the ajaxForm example application )
Improving
I have continued to decorate the control but the fancier it became, the sample value gets lost. However this one seems to be a good compromise still. The above control displays the “Loading…” text during the AJAX request.
def ajaxFilteredList(sensitivity: TimeSpan, size: Int, genFunc: String => List[(String, String)], selFunc: String => JsCmd): Elem = {
val rndID = "S"+System.nanoTime+"_"+randomString(3)
var value = ""
<div><script>var keyTimer;</script>
{text(value, x => {} ) %
("onkeyup" -> ("clearTimeout(keyTimer);keyTimer=" +
After( sensitivity,
SetElemById(rndID, JsRaw("'none'"),"style", "display")&
SetElemById("D"+rndID, JsRaw("'block'"),"style", "display")&
Run( ajaxCall("value", (value) =>
ReplaceOptions(rndID, genFunc(value), Empty)&
SetElemById("D"+rndID, JsRaw("'none'"),"style", "display")&
SetElemById(rndID, JsRaw("'block'"),"style", "display")
))).toJsCmd ))%
("style" -> "width:100%;")}
<div id={"D"+rndID} style="width:100%;height:100%;display:none;">
Loading....
</div>
{ajaxSelect(genFunc(value), Empty, selected => selFunc(selected) )%
("size" -> size) % ("style" -> "width:100%;") % ("id" -> rndID)}
</div>
}

