haskelldigestive-functors

List of checkboxes with digestive-functors


How do I use digestive functors to create a form that has a programmatically generated list of checkboxes, which would return a list. For example:

[x] Milk
[ ] Cereals
[x] Ground meat

would return ["Milk", "Ground meat"].

I'm expecting the type would be something like:

form :: (Functor m, Monad m) => [String] -> HappstackForm m Html BlazeFormHtml [String]

Solution

  • There is no standard way to do so, but digestive-functors is highly composable using the Applicative interface, so you can easily create what you want.

    You can define a checkBox which returns a Maybe String, i.e. the name of the element if it was checked.

    checkBox :: (Functor m, Monad m)
             => String -> HappstackForm m Html BlazeFormHtml (Maybe String)
    checkBox str = fmap maybeStr (inputCheckBox False) <++ label str
      where
        maybeStr True  = Just str
        maybeStr False = Nothing
    

    You can then loop over a list of strings to create a checkbox like this for each element in the list:

    listForm' :: (Functor m, Monad m)
              => [String]
              -> HappstackForm m Html BlazeFormHtml [Maybe String]
    listForm' = foldr (\x xs -> fmap (:) x <*> xs) (pure []) . map checkBox
    

    The catMaybes :: [Maybe a] -> [a] helps you to reduce the result further:

    listForm :: (Functor m, Monad m)
             => [String]
             -> HappstackForm m Html BlazeFormHtml [String]
    listForm = fmap catMaybes . listForm'
    

    And finally, we can instantiate the actual form:

    food :: [String]
    food = ["Milk", "Cereals", "Ground meat"]
    
    foodForm :: (Functor m, Monad m)
             => HappstackForm m Html BlazeFormHtml [String]
    foodForm = listForm food