Search code examples
haskellreflex

What is the proper way in reflex-dom to handle a modal dialog?


I am just starting with the reflex-dom library and I cannot quite figure out the proper and convenient way to work with dialogs.

Showing a dialog generally means adding a few elements to the end of <body> and removing it when the user clicks on some button, backdrop or presses e.g. escape. However doing this from some nested widget means somehow bubbling up the event ('show the dialog') to the top, which could be quite clumsy. Is there any other way to do it nicely? I just had a look at markup.rocks and that seems to use some JS/jQuery hacks.

I can decide not to use modal dialogs (it may not be a bad option after all), but for some things I may really need it.


Solution

  • Ultimately I found it quite easy:

    First, get the body element:

    getBody = do
      root <- askDocument
      Just nodelist <- getElementsByTagName root ("body" :: String)
      Just body <- nodelist `item` 0
      return body
    

    Then, assuming trigger is the Event that triggers opening the dialog and visible is a Dynamic t Bool that holds the current state, we can create a backdrop and move it to the back of body:

    backdropAttr <- forDyn visible (\vis -> if vis then ("class" =: "modal-backdrop fade in")
                                              else ("style" =: "display:none"))
    (backdrop, _) <- elDynAttr' "div" backdropAttr blank
    body <- getBody
    let moveBackdrop = (const $ (appendChild body (Just $ _el_element backdrop))) `fmap` trigger
    performEvent_ $ void `fmap` moveBackdrop