haskellreflex

How can I branch on the value inside a Reflex Dynamic?


in the simplest case, say I have a Dynamic t Bool, and when the value is true, I want a single empty div to exist, and when the value is false, I don't want there to be any dom element.

slightly more generally, if I have a Dynamic t (Either MyA MyB), and I have functions that know how to render given a Dynamic t MyA or a Dynamic t MyB, how to I call the appropriate function to render?


Solution

  • If you need to switch the widget you probably need one of:

    dyn :: MonadWidget t m => Dynamic t (m a) -> m (Event t a) Source
    

    or

    widgetHold :: MonadWidget t m => m a -> Event t (m a) -> m (Dynamic t a)
    

    Since you've mentioned you've got Dynamic at hand, we're gonna use dyn:

    app = do
      switched <- button "Alternate!"
      flag <- foldDyn ($) False (not <$ switched) -- just to have some Dynamic t Bool
      let w = myWidget <$> flag
      void $ dyn w
    
    myWidget :: MonadWidget t m => Bool -> m ()
    myWidget False = blank
    myWidget True = el "div" $ blank
    

    The basic rule is that, due to the higer-order nature of Reflex, if you want to swap-out something, you need to have Event/Dynamic that yields a widget as a value. That's why dyn takes Dynamic t (m a) as its parameter (and appropriately, widgetHold takes Event t (m a). And that's why we've mapped over Dynamic t Bool to have a dynamic that has our widget building action as a value.

    It's worth mentioning, that neither dynamic/widgetHold does virtual dom/diffing to speed the rendering. With reflex you can be more explicit about what updates what (a Dynamic/Event t Text can affect node text directly, without rerendering whole node) and you should take advantage of that. If not then large portions of page will be swapped and it can yield significant performance hit.