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)