ajaxpostyesodpage-refreshyesod-forms

POST request with no page refreshing in Yesod


The task is to create a registration form with pretty error handling.
I'm a newbie in Yesod, so the only way I found to do this is:

regForm :: Form User

getRegRExtra extraFormWidget = do
  (formWidget, enctype) <- case extraFormWidget of
                             Nothing -> generateFormPost regForm
                             Just val -> return val
  defaultLayout $ $(widgetFile "reg/reg")

getRegR = getRegRExtra Nothing

postRegR = do
  ((result, widget), enctype) <- runFormPostNoToken regForm 
  case result of
    FormSuccess person -> undefined
    _ -> getRegRExtra (Just (widget, enctype))

But there is a problem: Page refreshes on every submit while I want it to do this dynamically.
I know it could be fixed with the help of Ajax or Jquery,
but I'll lose all the benefits I get while using Yesod POST functions.
Is there any standard way to deal with that?


Solution

  • The solution is:

    -- Used for returning plain html as AJAX response.
    noLayout :: Widget -> Handler Html
    noLayout widget = do
      pc <- widgetToPageContent widget
      withUrlRenderer [hamlet| ^{pageBody pc} |]
    
    -- Replace a default event handler with the AJAX one.
    getRegR :: Handler Html
    getRegR = do
      ((res, formWidget), enctype) <- runFormPost regForm
      defaultLayout $ do
        $(widgetFile "reg/reg")
        addScriptRemote "https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"
        toWidget [julius|
          $(document).on('click', '.btn-important', function(e) {
            e.preventDefault();
            e.stopPropagation();
            $.ajax({
              type: 'POST',
              url:'@{RegR}',
              cache: false,
              dataType: 'html',
              data:$('#form-reg').serialize(),
              success: function(data) { $('#form-reg').html(data); }
            });
          }); |]
    
    postRegR :: Handler Html
    postRegR = do
      ((result, widget), enctype) <- runFormPostNoToken regForm
      noLayout widget