Javascript Yesod 中的警报
Javascript Alerts in Yesod
我有一个程序,用户可以在其中上传文件,对该文件进行一些验证,如果验证失败,我想通过 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
代码不会 "wait" 直到用户单击警报按钮(实际上警报甚至不显示)。
为了解决这个问题,我更改了 getAlertR :
getAlertR :: Handler Html
getAlertR = do
defaultLayout $ do
setTitle "ALERT!"
toWidgetBody [julius|
alert("Only text files are accepted");
location.assign("@{HomeR}");
|]
-- redirect HomeR
... 没问题。
但这是我的问题:是否有更多"Yesod-like"方法可以做到这一点而无需在 julius 脚本中进行路由?
这基本上是一个 "outside the scope of Yesod" 问题:如果您希望行为基于用户对警告框的响应而发生,则必须在 Javascript 中处理,您的方法可以在其中处理效果很好。一旦进入 Javascript 世界,就有 dozens/hundreds 种不同的方式来做到这一点(自动使用计时器?使用页面上的通知消息而不是单独的对话框?等等),但您无能为力在服务器端检查用户是否在没有 Javascript 支持的情况下单击了按钮。
我有一个程序,用户可以在其中上传文件,对该文件进行一些验证,如果验证失败,我想通过 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
代码不会 "wait" 直到用户单击警报按钮(实际上警报甚至不显示)。
为了解决这个问题,我更改了 getAlertR :
getAlertR :: Handler Html
getAlertR = do
defaultLayout $ do
setTitle "ALERT!"
toWidgetBody [julius|
alert("Only text files are accepted");
location.assign("@{HomeR}");
|]
-- redirect HomeR
... 没问题。
但这是我的问题:是否有更多"Yesod-like"方法可以做到这一点而无需在 julius 脚本中进行路由?
这基本上是一个 "outside the scope of Yesod" 问题:如果您希望行为基于用户对警告框的响应而发生,则必须在 Javascript 中处理,您的方法可以在其中处理效果很好。一旦进入 Javascript 世界,就有 dozens/hundreds 种不同的方式来做到这一点(自动使用计时器?使用页面上的通知消息而不是单独的对话框?等等),但您无能为力在服务器端检查用户是否在没有 Javascript 支持的情况下单击了按钮。