Skip to content
Find file
Fetching contributors…
Cannot retrieve contributors at this time
128 lines (122 sloc) 5.26 KB
import stdlib.themes.bootstrap
/**
* This is the core function here. It takes a list of options and let's the user
* select one of them. Upon selecting any item it calls the supplied callback
* with the selected value.
*
* @param id The id of the selection element; you can provide either [{id: value}]
* to generate an element with the given [value] id, or [{autogen}],
* in which case a (random) id will be generated by this function.
* @param options A list of values of an arbitrary type. Those will be the values
* that the user can choose from.
* @param callback A callback that will be called every time user makes selection.
* It has a single argument, which is the selected value.
* @return The function returns XHTML snippet with the selection among given options.
*
* EXERCISES:
* - As it is this function just renders the options with a default conversion
* to xhtml (which btw. can be customized with xmlizer functions!); what would
* you do if you need more control over the XHTML generated for every option?
* Try implementing it!
* - The callback is called every time the user changes his selection. Another
* useful interface would be to be able at any time to learn what's the user's
* selection. How would you provide this functionality?
*
* HINT: Opa is fully type-safe, however interacting with DOM/user is not.
* Writing proper auxiliary functions, such as this one, to hide this
* fact from the rest of the program and provide type-safe abstraction
* is crucial (and one day will probably be accomplished by a UI library
* for Opa).
*/
function select( // HINT: Such variants arguments are great way to make functions
// more flexible and reduce the number of variants of functions
({string id} or {autogen}) id,
list('a) options,
('a -> void) callback
)
{
// the final id of this element
sel_id =
match (id) {
case {id: user_id}: user_id; // take user provided value
case {autogen}: Dom.fresh_id() // take a fresh DOM value
}
// this function renders a single option; it also assigns to it a given value
function render_option(i, o) {
<option value={i}>{o}</>
}
// this function will be called on every selection change
function changed(_evt) {
// when rendering we gave options successive numerical values, so to learn
// which one was selected we just take the value of the selection, convert
// it to numerical value 'n' and take n'th element from the provided list of
// options
sel_val = List.unsafe_get(String.to_int(Dom.get_value(#{sel_id})), options);
callback(sel_val);
}
// Finally the <select> itself, with [onchange] event and the list of options
<select id={sel_id} onchange={changed}>
{List.mapi(render_option, options)}
</>
}
/**
* Callback function for favorite number choice
*
* @param number Selected number
* @return Nothing, but as a side-effect changes the help text for the selection
* informing which number was chosen
*/
// HINT: we will use those as callback functions to select function above.
// However, beware of putting those function inside the page function itself;
// page is used to generate the HTML response to the client and hence will
// live on the server. However, this callback function will be called every
// time selection is changed so we better make sure it's on the client
// (otherwise a round-trip to the server will occur with every selection
// change). To do that we can annote it with the 'client' keyword, however
// in this case it's not neccessary as Opa will put it on the client anyway.
function selected_num(int number) {
#selectNumMsg = <>You selected number: {number}</>
}
/**
* Callback function for favorite color choice
*
* @param color Selected color
* @return Nothing, but as a side-effect changes the help text for the selection
* informing which color was chosen
*/
function selected_color(string color) {
#selectColorMsg = <>You selected color: {color}</>
}
/**
* This is the main page. It's just a bunch of Bootstrap compatible XHTML markup,
* using the [select] function that we defined above.
*/
function page() {
list(int) numbers = [2, 3, 4, 5, 6, 7, 8, 9];
list(string) colors = ["Red", "Purple", "Pink", "Orange", "Yellow", "Green", "Blue"];
<div class=container>
<form class=form-horizontal>
<legend>Simple selection demo with Opa</>
<fieldset>
<div class=control-group>
<label class=control-label for=select01>Your favorite number?</>
<div class=controls>
{select({id: "selectNum"}, numbers, selected_num)}
<p id=#selectNumMsg class=help-block>You did not make any selection</>
</>
</>
<div class=control-group>
<label class=control-label for=select01>Your favorite color?</>
<div class=controls>
{select({id: "selectColor"}, colors, selected_color)}
<p id=#selectColorMsg class=help-block>You did not make any selection</>
</>
</>
</>
</>
</>
}
/**
* Finally, a simple one-page server
*/
Server.start(Server.http, {title: "Form selection in Opa", ~page});
Something went wrong with that request. Please try again.