Thursday, January 03, 2013

MFlow active widgets example


The new module MFlow.Forms.Widgets in the package MFlow  whose last version is in GtHub, (reference below) contains active widgets that can manage other widgets in order to compose complex dynamic applications. A widget is composed of form elements, links and scripts that return statically typed results.

 Now, an example of use of the active widget wEditList, described here.  This widget can manage a list of widgets of the same type. It can add or delete them. The result, when the list is sent to the server, is the sublist of the validated elements results.

In this case, the widget managed by wEditList is a row of a table with three elements: an Int input text, a String input text and a delete link. the widget is codified using blaze.html and the MFlow input fields.

The delete link  invokes a javascript event that delete the entire row.

There is a "add" link that add a new row to the list. To be recognized by the wEditList widget, it has to have the identifier "wEditListAdd"



grid = do
  let row _= tr <<< ( (,) <$> tdborder <<< getInt (Just 0)
                         <*> tdborder <<< getString (Just "text")
                         <++ tdborder << delLink)

      delLink= a ! href "#"
                 ! onclick  "this.parentNode.parentNode\
                    \.parentNode.removeChild\
                    \(this.parentNode.parentNode)"
                 << text "delete"
      tdborder= td ! At.style  "border: solid 1px"

      addLink= a ! href "#"
                 ! At.id "wEditListAdd"
                 << text "add"

Note the use of (,) and the applicative operators <$> and <*> over the form elements getInt and getString, which
compose a result of type (Int,String). There are also formatting operators <<< which encloses the form elements within a table colum element 'tborder' which is a 'td' element with some style. The ability to mix formatting and applicative operators is a unique feature of MFlow. It becomes quite intuitive to use after a while. A knowledge of  applicative operators is necessary. While <<< encloses a form element (or a wlink) in a html tag,  << encloses ordinary html, and this is why dellink, an ordinary html link is preceded by <<  . Finally the operator <++ append html formatting to a widget.

Here is how the widget looks with two initial elements:


add
delete
delete

Submit

This is how the wEditList is invoked with the row element as parameter. the 'table' holds the elements in this case. A initial list of two elements with empty strings,that are ignored, means that two elements will be show at the beginning. Finally, a submitButton will send the form result when pressed. To glue these components, the operator ++> prepends html to the widget and the operator <** is an applicative operator similar to <* which do not care about the validation result of the button (<* could have been used in this case). See Control.Applicative for the Applicative concept and the applicative operators.

r <- ask $ addLink ++> ( wEditList table  row ["",""]) <** submitButton "submit"

r will have the result. When I click add, two times and  edit some of the fields, the look is as follows:

add
delete
delete
delete
delete


Submit

if we add an additional line to print the result in a new web page. after pressing the submit button:

ask $   p << (show r ++ " returned")


The page will show this result:

[(1,"text1"),(2,"text2"),(3,"text3"),(4,"text4")] returned

The complete code is part of demos.Blaze.hs. 


This example uses the last version of MFlow at https://github.com/agocorona/MFlow.
It uses the last version of  Workflow  https://github.com/agocorona/Workflow


grid = do
  let row _= tr <<< ( (,) <$> tdborder <<< getInt (Just 0)
                          <*> tdborder <<< getString (Just "text")
                          <++ tdborder << delLink)
      addLink= a ! href "#"
                 ! At.id "wEditListAdd"
                 << text "add"
      delLink= a ! href "#"
                 ! onclick
                    "this.parentNode.parentNode\
                    \.parentNode.removeChild\
                    \(this.parentNode.parentNode)"
                 << text "delete"
      tdborder= td ! At.style  "border: solid 1px"

  r <- ask $ addLink ++> ( wEditList table  row ["",""]) <** submitButton "submit"
  ask $   p << (show r ++ " returned")
      ++> wlink () (p << text " back to menu")


No comments: