jaspervdj / digestive-functors

A general way to consume input using applicative functors
149 stars 71 forks source link

Checkboxes do not work at all #138

Closed mrkkrp closed 7 years ago

mrkkrp commented 7 years ago

Consider:

reportFieldsForm :: Monad m => Form Text m ReportFields
reportFieldsForm = ReportFields
  <$> "userId"       .: yep
  <*> "login"        .: yep
  <*> "email"        .: yep
  <*> "lastAccessed" .: yep
  <*> "loginCount"   .: yep
  where
    yep = bool (Just True)

This selects which fields to show in some next step, handler code:

handleReportSelectFields :: Handler App App ()
handleReportSelectFields = do
  (view, _) <- runForm "reportFields" reportFieldsForm
  renderWithSplices "admin/report/selectFields" $
    formSplices view

The templates goes like this:

<apply template="base">
  <div class="col-md-6">
    <h1>Reports</h1>
    <div class="panel panel-default">
      <div class="panel-heading">
        <h4>Select variables to include in the report</h4>
      </div>
      <div class="panel-body">
        <dfIfChildErrors>
          <div class="alert alert-danger">
            <dfChildErrorList/>
          </div>
        </dfIfChildErrors>
        <dfForm method="GET" action="/admin/report/preview">
          <div class="checkbox">
            <dfLabel ref="userId">
              <dfInputCheckbox ref="userId"/>
              User ID
            </dfLabel>
          </div>
          <div class="checkbox">
            <dfLabel ref="login">
              <dfInputCheckbox ref="login"/>
              Login
            </dfLabel>
          </div>
          <div class="checkbox">
            <dfLabel ref="email">
              <dfInputCheckbox ref="email"/>
              Email
            </dfLabel>
          </div>
          <div class="checkbox">
            <dfLabel ref="lastAccessed">
              <dfInputCheckbox ref="lastAccessed"/>
              Last time accessed
            </dfLabel>
          </div>
          <div class="checkbox">
            <dfLabel ref="loginCount">
              <dfInputCheckbox ref="loginCount"/>
              Login count
            </dfLabel>
          </div>
          <dfInputSubmit class="btn btn-primary" type="submit" value="Show me"/>
        </dfForm>
      </div>
    </div>
  </div>
</apply>

And it looks like this:

reports

In the address bar I see the following:

http://localhost:8000/admin/report/preview?reportFields.userId=on&reportFields.login=on&reportFields.email=on&reportFields.lastAccessed=on&reportFields.loginCount=on

This form however fails to parse and always returns Nothing:

handleReportPreview :: Handler App App ()
handleReportPreview = do
  (view, rf) <- runForm "reportFields" reportFieldsForm
  liftIO (print rf) -- <--- here, returns Nothing, always
  renderWithSplices "admin/report/selectFields" $
    formSplices view

No errors are ever displayed and if I change selections they are reset to the default “all set” state once I hit the “Show me” button.

What is going on?

cimmanon commented 7 years ago

It's because you're using GET (and Snap). Change your form to use POST and you'll see that it works as expected. You can find an example of how to get your form to run off of the GET request with Snap here: https://github.com/jaspervdj/digestive-functors/issues/80

See also: https://github.com/jaspervdj/digestive-functors/issues/116

mrkkrp commented 7 years ago

Thank you @cimmanon, your hack worked. I know that using the Snap framework is a mistake, but unfortunatelly I'm messing with an existing system and I cannot change the framework :-(