У меня есть программа, в которой пользователь может загрузить файл, происходит некоторая проверка этого файла, и если проверка не удалась, я хотел бы предоставить пользователю обратную связь через предупреждающее сообщение javascript, а не через сообщение, встроенное в html сам.
В идеале, как только пользователь подтвердит получение предупреждающего сообщения (нажав кнопку предупреждения), программа может перенаправить его на другой маршрут.
К сожалению, кажется, что перенаправление происходит сразу, без паузы, пока пользователь не нажмет кнопку оповещения, поэтому оповещение вообще пропускается.
Вот простой фрагмент, иллюстрирующий проблему: пользователя просят выбрать файл. Если это текстовый файл, отображается его имя, в противном случае создается предупреждение.
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
import Yesod
import Control.Concurrent.STM (TVar, newTVarIO, readTVarIO, atomically, writeTVar)
import Data.Text (Text)
data App = App (TVar Text)
mkYesod "App" [parseRoutes|
/ HomeR GET POST
/alert AlertR GET
|]
instance Yesod App
instance RenderMessage App FormMessage where
renderMessage _ _ = defaultFormMessage
getHomeR :: Handler Html
getHomeR = do
(formWidget, formEncType) <- generateFormPost uploadForm
App ttxt <- getYesod
txt <- liftIO $ readTVarIO ttxt
liftIO $ print txt
defaultLayout $ do
[whamlet|
<h1>Text file name: #{txt}
<p>
<form method=post action=@{HomeR} enctype=#{formEncType}>
^{formWidget} #
<input type="submit" value="Upload File Name">
|]
postHomeR :: Handler Html
postHomeR = do
((result, _), _) <- runFormPost uploadForm
case result of
FormSuccess fi -> do
app <- getYesod
case fileContentType fi of
"text/plain" -> updateFileName app $ fileName fi
_ -> redirect AlertR
_ -> return ()
redirect HomeR
updateFileName :: App -> Text -> Handler ()
updateFileName app@(App ttxt) txtnew =
liftIO . atomically $ writeTVar ttxt txtnew
getAlertR :: Handler Html
getAlertR = do
defaultLayout $ do
setTitle "ALERT!"
toWidgetBody [julius|
alert("Only text files are accepted");
|]
redirect HomeR
uploadForm = renderDivs $ fileAFormReq "file"
main :: IO ()
main = do
ttxt <- newTVarIO "nil"
warp 3000 $ App ttxt
Так что это не работает, и в getAlertR код redirect HomeR
не «ждет», пока пользователь не нажмет кнопку предупреждения (на самом деле предупреждение даже не отображается).
Чтобы обойти эту проблему, я изменил getAlertR следующим образом:
getAlertR :: Handler Html
getAlertR = do
defaultLayout $ do
setTitle "ALERT!"
toWidgetBody [julius|
alert("Only text files are accepted");
location.assign("@{HomeR}");
|]
-- redirect HomeR
... который работает нормально.
Но вот мой вопрос: есть ли более "Йесод-подобный" способ сделать это без маршрутизации внутри скрипта julius?