I have a scaffolded site and I am using this snippet of code in the Home Handler.
{-# LANGUAGE TupleSections, OverloadedStrings #-}
module Handler.Home where
import Import
import Yesod.Auth
getHomeR :: Handler RepHtml
getHomeR = do
defaultLayout $ do
maid <- maybeAuthId
setTitle "Welcome!"
$(widgetFile "homepage")
I would like to access maid in my homepage.hamlet file. However, I get the following error:
Handler/Home.hs:10:17:
Couldn't match expected type `WidgetT site0 IO t0'
with actual type `HandlerT master0 IO (Maybe (AuthId master0))'
In a stmt of a 'do' block: maid <- maybeAuthId
In the second argument of `($)', namely
`do { maid <- maybeAuthId;
setTitle "Welcome!";
$(widgetFile "homepage") }'
In a stmt of a 'do' block:
defaultLayout
$ do { maid <- maybeAuthId;
setTitle "Welcome!";
$(widgetFile "homepage") }
I get the above error message whether or not I put any contents inside homepage.hamlet. Instead of using $(widgetFile "homepage"), if I paste the whamlet code snippet from the Yesod Book (Auth section), it works fine.
If I remove the call to maybeAuthId, the issue goes away too. I am guessing it is something to do with the call to maybeAuthId and using the widgetFile but I am not sure how to fix the issue. Any help appreciated.
Thanks!
maybeAuthId lives in the Handler monad, and the inside of defaultLayout is a Widget, which is why you have a mismatch. You could do one of the following:
Convert the Handler action to a Widget action using handlerToWidget
Move the maybeAuthId call to before defaultLayout
Related
Since IO can not be used inside Yesod Template, how can I display a simple current time on a page?
In my .hamlet file, something like:
<h2>
#{show $ getCurrentTime }
getCurrentTime :: IO UTCTime
In other words, you need to run the IO action outside of the template.
That outside means the template's handler. So I would write like this.
-- Home.hs
getHomeR = do
time <- liftIO getCurrentTime
defaultLayout $(widgetFile "homepage")
-- homepage.hamlet
<h2>#{show time}
I just initialized a Yesod project (no database) using yesod init.
My HomeR GET handler looks like this:
getHomeR :: Handler Html
getHomeR = do
(formWidget, formEnctype) <- generateFormPost sampleForm
let submission = Nothing :: Maybe (FileInfo, Text)
handlerName = "getHomeR" :: Text
defaultLayout $ do
aDomId <- newIdent
setTitle "Welcome To Yesod!"
$(widgetFile "homepage")
When using yesod devel, I can access the default homepage at http://localhost:3000/.
How can I modify the handler listed above to retrieve (and display) a HTTP GET query parameter like id=abc123 when accessing this URL:
http://localhost:3000/?id=abc123
Note: This question was answered Q&A-style and therefore intentionally doesn't show research effort!
I'll show two different methods to achieve this. For both, you'll need to add this code to your template, e.g. in homepage.hamlet:
Note that it is not guaranteed there is any id parameter present when accessing the URL, therefore the type resulting from both methods is Maybe Text. See the Shakespearean template docs for a detailed explanation of the template parameters.
Method 1: lookupGetParam
The easiest way you can do this is using lookupGetParam like this:
idValueMaybe <- lookupGetParam "id"
When using the default setting as generated by yesod init, idValueMaybe needs to be defined in both getHomeR and postHomeR if idValueMaybe is used in the template.
Your HomeR GET handler could look like this:
getHomeR :: Handler Html
getHomeR = do
idValueMaybe <- lookupGetParam "id"
(formWidget, formEnctype) <- generateFormPost sampleForm
let submission = Nothing :: Maybe (FileInfo, Text)
handlerName = "getHomeR" :: Text
defaultLayout $ do
aDomId <- newIdent
setTitle "Welcome To Yesod!"
$(widgetFile "homepage")
Method 2: reqGetParams
Instead of looking up the query parameters by name, you can also retrieve a list of query key/value pairs using reqGetParams. This can be advantageous in certain situations, e.g. if you don't know all possible keys in advance. Using the standard lookup function you can easily lookup a certain key in that list.
The relevant part of your code could look like this:
getParameters <- reqGetParams <$> getRequest
let idValueMaybe = lookup "id" getParameters :: Maybe Text
Your getHomeR could look like this:
getHomeR :: Handler Html
getHomeR = do
getParameters <- reqGetParams <$> getRequest
let idValueMaybe = lookup "id" getParameters :: Maybe Text
(formWidget, formEnctype) <- generateFormPost sampleForm
let submission = Nothing :: Maybe (FileInfo, Text)
handlerName = "getHomeR" :: Text
defaultLayout $ do
aDomId <- newIdent
setTitle "Welcome To Yesod!"
$(widgetFile "homepage")
I am trying to get the basic example from http://egonschiele.github.io/HandsomeSoup/ to work:
main = do
doc <- fromUrl "http://www.google.com/search?q=egon+schiele"
links <- runX $ doc >>> css "h3.r a" ! "href"
mapM_ putStrLn links
I have tried to reproduce the example like so:
module Main (main) where
import Text.HandsomeSoup
import Text.XML.HXT.Core
import Control.Monad
main = do
doc <- fromUrl "http://www.google.com/search?q=egon+schiele"
links <- runX $ doc >>> css "h3.r a" ! "href"
mapM_ putStrLn links
But, I am getting the following error:
$ runhaskell Main.hs
Main.hs:8:21:
Couldn't match expected type `IOSLA (XIOState ()) XmlTree b0'
with actual type `hxt-9.3.0.1:Data.Tree.NTree.TypeDefs.NTree
hxt-9.3.0.1:Text.XML.HXT.DOM.TypeDefs.XNode'
In the first argument of `(>>>)', namely `doc'
In the second argument of `($)', namely
`doc >>> css "h3.r a" ! "href"'
In a stmt of a 'do' block:
links <- runX $ doc >>> css "h3.r a" ! "href"
But I really can't seem to figure out what's going on.
Function fromUrl has type fromUrl :: String -> IOSArrow XmlTree (NTree XNode).
So IOSArrow XmlTree (NTree XNode) is not clear IO-action.
Simplest way fix it - use let statement instead:
import Text.HandsomeSoup
import Text.XML.HXT.Core
main :: IO ()
main = do
let doc = fromUrl "http://www.google.com/search?q=egon+schiele"
links <- runX $ doc >>> css "h3.r a" ! "href"
mapM_ putStrLn links
I am just started with Yesod, I am following this tutorial:http://yannesposito.com/Scratch/en/blog/Yesod-tutorial-for-newbies/
I get this error:
Handler/Blog.hs:32:17:
Couldn't match type `handler' with `GHandler App App'
`handler' is a rigid type variable bound by
the type signature for postBlogR :: handler RepHtml
at Handler/Blog.hs:29:14
Expected type: handler [Entity Article]
Actual type: GHandler App App [Entity Article]
In a stmt of a 'do' block:
articles <- runDB $ selectList [] [Desc ArticleTitle]
In the expression:
do { articles <- runDB $ selectList [] [Desc ArticleTitle];
(articleWidget, enctype) <- generateFormPost entryForm;
defaultLayout $ do { $(widgetFile "articles") } }
In an equation for `postBlogR':
postBlogR
= do { articles <- runDB $ selectList [] [Desc ArticleTitle];
(articleWidget, enctype) <- generateFormPost entryForm;
defaultLayout $ do { ... } }
this is my Blog.hs:
module Handler.Blog
( getBlogR
, postBlogR
)
where
import Import
-- to use Html into forms
import Yesod.Form.Nic (YesodNic, nicHtmlField)
instance YesodNic App
entryForm :: Form Article
entryForm = renderDivs $ Article
<$> areq textField "Title" Nothing
<*> areq nicHtmlField "Content" Nothing
-- The view showing the list of articles
getBlogR :: Handler Html
getBlogR = do
-- Get the list of articles inside the database.
articles <- runDB $ selectList [] [Desc ArticleTitle]
-- We'll need the two "objects": articleWidget and enctype
-- to construct the form (see templates/articles.hamlet).
(articleWidget, enctype) <- generateFormPost entryForm
defaultLayout $ do
$(widgetFile "articles")
postBlogR :: handler RepHtml
postBlogR = do
-- Get the list of articles inside the database.
articles <- runDB $ selectList [] [Desc ArticleTitle]
-- We'll need the two "objects": articleWidget and enctype
-- to construct the form (see templates/articles.hamlet).
(articleWidget, enctype) <- generateFormPost entryForm
defaultLayout $ do
$(widgetFile "articles")
my routes:
/static StaticR Static getStatic
/auth AuthR Auth getAuth
/favicon.ico FaviconR GET
/robots.txt RobotsR GET
/ HomeR GET POST
/echo/#Text EchoR GET
/mirror MirrorR GET POST
/blog BlogR GET POST
/blog/#ArticleId ArticleR GET
and my models:
User
ident Text
password Text Maybe
UniqueUser ident
Email
email Text
user UserId Maybe
verkey Text Maybe
UniqueEmail email
Article
title Text
content Html
deriving
-- By default this file is used in Model.hs (which is imported by Foundation.hs)
I think, you just have to fix your type signature for postBlogR to Handler RepHtml. Names starting with lower case letters are reserved for type variables in type signatures, so it cannot be deduced right here.
I'm trying to use CKEditor in my Yesod application. Data from CKEditor is returned to the server via Textarea, I then store it as Html in database. My problem is I do know know how to display the Html algebraic data type once I retrieve it from database in the handler. I've been reading this tutorial, but it will only display the Html as a big long string, not as markup.
Note: titleA and contextA are the variable that I want to display in article-local-display.
contextA is the Html algebraic data type
PS: Do I need to transform Html to hamlet in order to render?
module Handler.Article where
import Import
import Data.Text (unpack)
import Data.Time (getCurrentTime)
import Data.String (fromString)
getArticleR :: Handler RepHtml
getArticleR = do
defaultLayout $ do
setTitle "Search For Article"
$(widgetFile "header")
$(widgetFile "article")
postArticleR :: Handler RepHtml
postArticleR = do
redirect ArticleR
getArticleLocalR :: Handler RepHtml
getArticleLocalR = do
articles <- runDB $ selectList ([] :: [Filter Article]) [Desc ArticleTime]
defaultLayout $ do
setTitle "Local Article"
$(widgetFile "header")
$(widgetFile "article-local")
getArticleLocalDisplayR :: ArticleId -> Handler RepHtml
getArticleLocalDisplayR articleId = do
article <- runDB $ get404 articleId
let titleA = articleTitle article
contextA = articleContext article
defaultLayout $ do
setTitle "Article"
$(widgetFile "header")
$(widgetFile "article-local-display")
getArticleLocalCreateR :: Handler RepHtml
getArticleLocalCreateR = do
defaultLayout $ do
setTitle "Create article"
addScript $ StaticR ckeditor_ckeditor_js
$(widgetFile "header")
$(widgetFile "article-local-create")
postArticleLocalCreateR :: Handler RepHtml
postArticleLocalCreateR = do
articleForm <- runInputPost $ ArticleForm <$> ireq textField "title" <*> ireq textareaField "editor1"
now <- liftIO getCurrentTime
let titleA = title articleForm
html = toHtml $ unTextarea $ context articleForm
_ <- runDB $ insert $ Article titleA html now
redirect ArticleLocalR
data ArticleForm = ArticleForm {
title :: Text,
context :: Textarea
}
deriving Show
models file:
Article
title Text
context Html
time UTCTime
deriving
article-local-display.hamlet
<h1>#{titleA}
<article>#{contexA}
So I changed the context from Html to Text.
Article
title Text
context Text
time UTCTime
deriving
Then added preEscapedText when using the value.
let contextA = preEscapedText $ articleContext article
Now it's displaying properly.