yesodweb / shakespeare

Haml-like template files that are compile-time checked
http://www.yesodweb.com/book/shakespearean-templates
MIT License
136 stars 76 forks source link

Hamlet puts <title> to <body> #249

Closed rtentser closed 4 years ago

rtentser commented 4 years ago

I'm not sure if it's a bug or i'm just doing something wrong. I'm trying to learn Yesod and get a strange html.

Source:

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes       #-}
{-# LANGUAGE TemplateHaskell   #-}
{-# LANGUAGE TypeFamilies      #-}

import           Yesod

data App =
  App

mkYesod
  "App"
  [parseRoutes|
    / HomeR GET
  |]

instance Yesod App

html =
  [hamlet|
    $doctype 5
    <html>
      <head>
        <title>My title!
      <body>
        <p>My text.
  |]

getHomeR :: Handler Html
getHomeR = defaultLayout $ toWidget html

main :: IO ()
main = warp 3000 App

HTML in browser:

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title></title>
  </head>
  <body>
    <title>My title!</title>
    <p>My text.</p>
  </body>
</html>

You can see that <title> tag in <head> is empty and <body> has other <title> tag with "My title!" in it,

snoyberg commented 4 years ago

Please look at the examples of using defaultLayout in the Yesod book:

  1. You need to call setTitle
  2. You should not include the <html>, <head>, or <body> tags in the whamlet you pass to defaultLayout.
rtentser commented 4 years ago

defaultLayout overrides this tags?

In "Shakespearean Templates" chapter in hamlet examples this tags are filled. It's confusing.

snoyberg commented 4 years ago

Please see the "using widgets" section here.

https://www.yesodweb.com/book/widgets

bitemyapp commented 4 years ago

@rtentser the issue is that there's some distance between the simplest possible example of using a library as opposed to how you use it in a real application. It's pretty common for a basic tutorial on a templating library to start with an example that doesn't have a separate base template.

You go to the first result for "Django templating" on Google (https://docs.djangoproject.com/en/3.0/topics/templates/) and it launches into project-level configuration stuff.

Hamlet doesn't use Jinja-style inheritance so when you want to factor out layers of a templating hierarchy (e.g. base -> authenticated pages -> user profile) you do it with function abstraction and widgets. The widgets are themselves usually the product of a whamlet quasiquoter and you can think of them as ready-to-render template fragments.

If, for example, I wanted to abstract out the footer to my base template helper I could take an argument named "footerWidget" with the widget type and use the ^{footerWidget} syntax to inject the fragment.

You can see an example of a base template using widgets here: https://gitlab.com/lorepub/moot/blob/master/src/Helpers/Views.hs#L19

Then in use:

Hope this helps.

rtentser commented 4 years ago

Thanks a lot for all your answers, they helps indeed. I understand now that it's expected behaviour and i need to dive deeper. I'll read suggested links. Thanks again.