我是Yesod的新手,似乎完全失去了Widgets,Handlers,Hamlets,WHamlets以及你有什么!这就是我要做的事情:
defaultLayout
因此,我尝试在Foundation.hs
中编写以下函数(代码布局是基本的yesod-sqlite
脚手架模板):
nav = do
globalStat <- handlerToWidget $ A2.getGlobalStat NWT.ariaRPCUrl
$(whamletFile "templates/navbar.hamlet)
A2.getGlobalStat :: IO GlobalStatResponse
这是template/navbar.hamlet
的样子:
<nav .navbar .navbar-default>
<div .container-fluid>
<p .navbar-right .navbar-text>
<span>
#{A2.glDownloadSpeed globalStat}
<i .glyphicon .glyphicon-arrow-down>
<span>
#{A2.glUploadSpeed globalStat}
<i .glyphicon .glyphicon-arrow-up>
<span .label .label-success>
On-the-watch
这是default-layout-wrapper.hamlet
的样子:
<!-- SNIP -->
<body>
<div class="container">
<header>
^{nav}
<div id="main" role="main">
^{pageBody pc}
<!-- SNIP -->
这是defaultLayout
的样子:
defaultLayout widget = do
master <- getYesod
mmsg <- getMessage
pc <- widgetToPageContent $ do
addStylesheet $ StaticR css_bootstrap_css
$(widgetFile "default-layout")
withUrlRenderer $(hamletFile "templates/default-layout-wrapper.hamlet")
但是,代码拒绝使用一个又一个类型错误进行编译。我已经尝试了很多hametFile
,whamletFile
,handerToWidget
,liftIO
的组合,甚至将导航功能放在 {{ 1}},但似乎没有任何效果。据我说,我当前的代码应该编译,但我显然不明白Yesod-Core类型是如何工作的。
我如何让它工作?更重要的是,我误解了什么概念?
修改1:
尝试将defaultLayout
功能修改为以下内容:
nav
但是,nav :: Handler Html
nav = do
globalStat <- liftIO $ A2.getGlobalStat NWT.ariaRPCUrl
$(hamletFile "templates/navbar.hamlet")
行defaultLayout
导致以下类型不匹配:
withUrlRenderer
编辑2:
尝试将 Couldn't match type ‘HandlerT App IO Html’
with ‘Text.Hamlet.Render (Route App) -> Html’
Expected type: HtmlUrl (Route App)
Actual type: Handler Html
In the first argument of ‘Text.Hamlet.asHtmlUrl’, namely ‘nav’
In a stmt of a 'do' block: Text.Hamlet.asHtmlUrl nav _render_a2ZY0 (intero)
的类型签名更改为:
nav
但是它导致了一个新的类型不匹配,在同一行:
nav :: Widget
nav = do
globalStat <- liftIO $ A2.getGlobalStat NWT.ariaRPCUrl
$(hamletFile "templates/navbar.hamlet")
编辑3:
这是 Couldn't match type ‘WidgetT App IO ()’
with ‘Text.Hamlet.Render (Route App) -> Html’
Expected type: HtmlUrl (Route App)
Actual type: Widget
In the first argument of ‘Text.Hamlet.asHtmlUrl’, namely ‘nav’
In a stmt of a 'do' block: Text.Hamlet.asHtmlUrl nav _render_a350l (intero)
的相关摘录:
-ddump-splices
\ _render_a28TE
-> do { asHtmlUrl (pageHead pc) _render_a28TE;
id ((Text.Blaze.Internal.preEscapedText . Data.Text.pack) "\n");
asHtmlUrl (pageBody pc) _render_a28TE;
id ((Text.Blaze.Internal.preEscapedText . Data.Text.pack) "\n");
asHtmlUrl testWidget2 _render_a28TE }
和(pageHead pc)
的类型为(pageBody pc)
答案 0 :(得分:1)
查看this SO question的答案。基本上你不能在模板中执行IO。
另请注意,defaultLayout
的类型为GHandler ...
且GHandler
为instance of MonadIO,因此您可以defaultLayout
使用liftIO
执行IO }}
我会尝试:
defaultLayout = do
...
globalStat <- liftIO $ handlerToWidget $ A2.getGlobalStat NWT.ariaRPCUrl
uploadSpeed <- liftIO $ A2.glUploadSpeed globalStat
downloadSpeed <- liftIO $ A2.glDownloadSpeed globalStat
...
withUrlRenderer $(hamletFile "templates/default-layout-wrapper.hamlet")
在templates/default-layout-wrapper.hamlet
:
...
^{nav uploadSpeed downloadSpeed}
...
nav
变成了类似的东西:
nav uploadSpeed downloadSpeed = $(whamletFile "templates/navbar.hamlet)
所以基本的想法是:
defaultLayout
liftIO
中完成所有IO
<强>更新强>
要模仿this example in the Yesod book,您需要像这样写navbar
:
navbar :: Widget
navbar = do
globalStat <- liftIO A2.getGlobalStat NWT.ariaRPCUrl
downloadSpeed <- liftIO A2.glDownloadSpeed globalStat
uploadSpeed <- liftIO A.glUploadSpeed
$(whamletFile "templates/navbar.hamlet)
在navbar.whamlet
中,请参阅#{uploadSpeed}
和#{downloadSpeed}
。
你不能在whamlet文件中执行IO。此外,您的A2函数是IO动作,但handlerToWidget需要HandlerT操作,因此您需要使用liftIO
转换这些调用。
更新2
有关在Widget中执行IO的工作示例,请参阅http://lpaste.net/169497。
答案 1 :(得分:0)
以下是我如何使用它。实际上我遇到了两个不同的问题:
default-layout-wrapper
hamletFile。这是在小部件中执行IO的解决方案:
nav :: Widget
nav = do
globalStat <- liftIO $ A2.getGlobalStat NWT.ariaRPCUrl
$(whamletFile "templates/navbar.hamlet")
注意:类型签名nav :: Widget
似乎是必要的,否则类型推断引擎可能会混淆,并为liftIO
操作推断出一种非常不同的类型(最初发生在我身上)。
对于第二个问题,我无法真正找到在default-layout-wrapper
hamletFile中引用Widget的解决方案。在呈现此特定hamletFile时,Widget monad已转换为PageContent
类型,现在需要Html url
类型才能将其与withUrlRenderer
一起呈现功能。基本上,我无法让Widget
和PageContent
撰写。但是,以下方法以不同的方式给了我想要的结果:
default-layout.hamlet:在此文件中添加了对nav
窗口小部件的调用。将一些元素从default-layout-wrapper
移动到此文件:
<div .container>
<header>
^{nav}
<div #main role="main">
$maybe msg <- mmsg
<div #message>#{msg}
^{widget}
default-layout-wrapper.hamlet:将此文件中的一些HTML元素移至default-layout
:
<!-- SNIP -->
<body>
<div class="container">
^{pageBody pc}
<!-- SNIP -->