[Ur] Existing examples laying the groundwork for building a Native Select Widget. Help is welcome on how to make this a Native *Databound* *Autocomplete* Widget ! :-)

Stefan Scott Alexander stefanscottalexx at gmail.com
Tue Jul 14 12:02:09 EDT 2015


TL;DR:

The code at these 2 links seems to point the way towards building a Native
Select Widget:

(1) https://github.com/urweb/gui/blob/master/select.ur

(2) https://github.com/urweb/urweb/blob/master/tests/cselect.ur

(3) However, even after building a new control combining the two examples
above, a 3rd ingredient would be needed: make the control *data-bound* (ie,
reading and writing to and from the SQL database).

(4) Finally, the above probably would only provide a *select* widget (where
the user can only select an existing option). So, a 4th functionality would
also be nice to have: *autocomplete* (a more flexible kind of widget, where
the user can also type in a sequence of characters, and the menu options
can be filtered).

The result would be a compact and hopefully efficient piece of code
providing a Native Databound Autocomplete Widget - an essential GUI
component, typically available to application developers in nearly all
database frameworks (examples of polished JavaScript libraries include
Select2 and twitter typeahead.js).

Any help on this would be greatly welcomed!

===

Hints towards an answer to the question I have been asking (on how to build
a Native / FRP Databound Autocomplete Widget in Ur/Web - or even a foreign
/ FFI one) have actually already been published, in 2011, by Adam, here:

https://github.com/urweb/gui/blob/master/select.ur

fun crender r =
    <xml><cselect source={r.Selected}>
      {List.mapX (fn r' => <xml><coption
value={r'.Key}>{[r'.Display]}</coption></xml>) r.Choices}
    </cselect></xml>

fun crender' r =
    <xml><cselect source={r.Selected}>
      {List.mapX (fn s => <xml><coption>{[s]}</coption></xml>) r.Choices}
    </cselect></xml>

and here:

https://github.com/urweb/urweb/blob/master/tests/cselect.ur

fun main () =
    s <- source "";
    return <xml><body>
      <cselect source={s} onchange={v <- get s; alert ("Now it's " ^ v)}>
        <coption>Wilbur</coption>
        <coption>Walbur</coption>
      </cselect>

      Hello, I'm <dyn signal={s <- signal s; return <xml>{[s]}</xml>}/>.
      I'll be your waiter for this evening.
    </body></xml>

This seems to be a good starting point for creating a Native Databound
Autocomplete Widget in Ur/Web.

However, this stuff is hard to find.

Remark:

By the way, you generally are going to want *two* columns in your dropdown
/ datalist / list of options - so you would also use the `value` attribute,
like so:

fun main () =
    s <- source "";
    return <xml><body>
      <cselect source={s} onchange={v <- get s; alert ("Now it's " ^ v)}>
        <coption value="WIIII">Wilbur</coption>
        <coption value="WAAAA">Walbur</coption>
      </cselect>

      Hello, I'm <dyn signal={s <- signal s; return <xml>{[s]}</xml>}/>.
      I'll be your waiter for this evening.
    </body></xml>

Fortunately this works as expected, and the text displayed in the browser
switches between:

Hello, I'm WIIII. I'll be your waiter for this evening.
Hello, I'm WAAAA. I'll be your waiter for this evening.

(1) Question:

How can this be made "data-bound" - ie how can this widget be connected to
reading and writing an SQL database?

I guess this could be an interesting exercise for the student to figure out
- and if no one else does I probably will manage to eventually, since it's
so incredibly important.

(2) Observation:

It's odd that the indispensable and ubiquitous *data-bound* version of the
nearly standard or universal Select Widget (or, the more flexible
Autocomplete Widget) - which is vitally important because it's used in
nearly all CRUD applications to allow the user to easily set the value of a
foreign-key field - would still be missing or forgotten after all these
years in the Ur/Web literature - because, after all, Ur/Web is supposedly
oriented towards web databases.

Try making an end-user-editable database without a Databound Select (or
Autocomplete) Widget. It's not practical, nobody does it.

(3) Observation:

The fact that one of the function names here is called 'render' is
interesting. This actually seems to be in line with the nomenclature in
most of the horde of JavaScript frameworks which have suddenly discovered
the virtues of being functional FP (and even trying to be
functional-reactive FRP). For example, a big deal is made about the
workings of the Mithril function 'render', etc.

Essentially this is all just using dataflow programming for GUI. It's
already been proven to be the most compact notionally and the most
efficient computationally.

It was also used for example in Arthur Stanley's k from kx.com in C on
Windows in the 1990s as well - developed for an investment bank in
Switzerland (that particular version, with the declarative
functional-reactive dataflow-style Win32 / Posix GUI, got discontinued - I
believe it was 2.4, I have a working copy around somewhere which I got off
archive.org years ago, plus I have the old PDFs showing the layouts.  It is
so cool to be able to specify a dynamic, interactive UI simply using a
matrix of controls linked to data, in just a few lines of code. The syntax
in that language k, for the two words corresponding to Ur/Web's `source`
and `signal` - aka Qt's `slot` and `signal`, etc. - was: `trigger` and
`dependency`.)

(4) Observation:

The code (which I've posted previously - it's at the end of the link below)
from a possibly related JavaScript front-end approach (in this case, RxJS +
Mithril - which is functional and "FRP-friendly"), may be suggestive here,
of how to best implement a native autocomplete widget more efficiently in
native Ur/Web

http://www.impredicative.com/pipermail/ur/2015-July/002047.html

Also, in particular, the "function pipeline" from the above RxJS+Mithril
code is suggestive:

var AutoComplete = {
  controller() {
    this.data = m.prop({});

    Rx.Observable.fromEvent(el, "keyup")
     .map(pluck("target")) /* get element */
     .filter(el => el.matches("input")) /* make sure it is the input */
     .map(pluck("value")) /* get element's value */
     .filter(val => val.length > 2) /* at least 3 chars */
     .debounce(250) /* debounce it */
     .distinctUntilChanged() /* ignore non character keyups */
     .flatMapLatest(searchGithub) /* fire request */
     .subscribe(this.data); /* set data prop with results */
  },
...

(5) Question:

How does combine the two fragments of Ur/Web code, such that when the user
changes the text in the data-entry part of the widget, the list of items in
the drop-down menu changes?

(6) Concern: I assume the the above Ur/Web code does indeed compile down to
using HTML5 <select> and <option>?

That might be a limitation, because it would mean that the user cannot
actually type keystrokes into an HTML5 <select>, they can only select an
existing item from the list (ie, this would *not* be a combo-box).

ie, there would be no "data-entry part of the widget" (in the case of a
<select> widget).

Actually, there might be a variety of mechanisms for producing this kind of
look and feel in a browser today:

- <select> widget
- <input> plus <datalist>   -  but not supported in Safari, and lacks
something related to the DOM

(7) Question:

Can the above Ur/Web code be used as the basis to implement a typeahead or
autocomplete widget (ie one where the user not only can select an existing
item from the list, but can also arbitrary text *into* the box).

If not, there might two possible solutions:

(8) Question:

(a) Can merely the *formatting* of HTML <select> and <options> be modified
on-the-fly so that it *looks* to the user like they're entering a sequence
of letters into box?

Ideally, I'd like to have it be like the follows, after the user typed m o
n a:

mona
----
monaRCHY
monaCO
mona LISA
monaRCH BUTTERFLY

This can of course be done if the top control is user-editable (such as an
<input>). But it might not be possible for the user to type into a <select>.

(b) Or, if the user can't "type into" a <select> then this would mean some
other HTML tag(s) would have to be used (eg, <input> and HTML5 <datalist>).

I'm not sure how these HTML controls are produced by Ur/Web syntax.

(9) Observation:

Figuring out just the correct names and locations of the best components to
use for front-end development is like a "scavenger hunt" or a "wild goose
chase" (two weird but popular American idioms... speaking of idioms... but
I digress :-)


(10) Conclusion:

The above Ur/Web code fragments do at least seem to provide a general
outline (ie, FRP skeleton - or perhaps one should say: FRP wiring) for an
autocomplete widget.

Probably only another few lines are required to implement sophisticated
data-bound behavior - and maybe with some clever use of CSS, it could head
in the direction of what we see with Select2 and Twitter typeahead.js (I
can dream, can't I?)

###
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.impredicative.com/pipermail/ur/attachments/20150714/b3469cfa/attachment.html>


More information about the Ur mailing list