I'm new to Yesod and seem to be completely lost with Widgets, Handlers, Hamlets, WHamlets, and what have you! Here's what I'm trying to do:
- Every page on my site needs to have a navbar, which leads me to believe that the correct place for implementing this should be
defaultLayout
- Now, this navbar needs to display some information that is obtained from an IO action (it's an RPC call which gives this data, to be more specific).
Therefore, I tried writing the following function in Foundation.hs
(the code layout is the basic yesod-sqlite
scaffolding template):
nav = do
globalStat <- handlerToWidget $ A2.getGlobalStat NWT.ariaRPCUrl
$(whamletFile "templates/navbar.hamlet)
A2.getGlobalStat :: IO GlobalStatResponse
Here's what template/navbar.hamlet
looks like:
<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
Here's what default-layout-wrapper.hamlet
looks like:
<!-- SNIP -->
<body>
<div class="container">
<header>
^{nav}
<div id="main" role="main">
^{pageBody pc}
<!-- SNIP -->
Here's what defaultLayout
looks like:
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")
However, the code refuses to compile with one type-error after another. I've tried a lot of combinations of hametFile
, whamletFile
, handerToWidget
, liftIO
, even placing the nav function inside defaultLayout
, but nothing seems to work. According to me my current code should compile, but I've obviously not understood how the Yesod-Core types are working.
How do I get this to work? And more importantly, what concept have I misunderstood?
Edit 1:
Have tried modifying the nav
function to the following:
nav :: Handler Html
nav = do
globalStat <- liftIO $ A2.getGlobalStat NWT.ariaRPCUrl
$(hamletFile "templates/navbar.hamlet")
But, it results in the following type mismatch in defaultLayout
on the line with withUrlRenderer
:
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)
Edit 2:
Tried changing the type signature of nav
to:
nav :: Widget
nav = do
globalStat <- liftIO $ A2.getGlobalStat NWT.ariaRPCUrl
$(hamletFile "templates/navbar.hamlet")
But it results in a new type-mismatch, in the same line:
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)
Edit 3:
Here's a relevant snippet from -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 }
The type of (pageHead pc)
and (pageBody pc)
is HtmlUrl (Route App)