Оповещения 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 не «ждет», пока пользователь не нажмет кнопку предупреждения (на самом деле предупреждение даже не отображается).

Чтобы обойти эту проблему, я изменил getAlertR следующим образом:

getAlertR :: Handler Html
getAlertR = do
    defaultLayout $ do
        setTitle "ALERT!"
        toWidgetBody [julius| 
                        alert("Only text files are accepted");
                        location.assign("@{HomeR}"); 
                     |]
    -- redirect HomeR 

... который работает нормально.

Но вот мой вопрос: есть ли более "Йесод-подобный" способ сделать это без маршрутизации внутри скрипта julius?


person Janthelme    schedule 08.01.2016    source источник


Ответы (1)


По сути, это проблема «выходящая за рамки Yesod»: если вы хотите, чтобы поведение происходило на основе ответа пользователя на окно предупреждения, оно должно обрабатываться в Javascript, в котором ваш подход может работать достаточно хорошо. Находясь в мире Javascript, существуют десятки/сотни различных способов сделать это (автоматическое использование таймера? использование сообщения уведомления на странице вместо отдельного диалогового окна? и т. д.), но вы ничего не можете сделать на стороне сервера, чтобы проверить это. пользователь нажал кнопку без поддержки Javascript.

person Michael Snoyman    schedule 09.01.2016