haskellblaze-htmlihp

PostsController for href attribute


The following:

instance View EditView where
    html EditView { .. } = [hsx|
        <nav>
            <ol class="breadcrumb">
                <li class="breadcrumb-item"><a href={PostsAction}>Posts</a></li>
                <li class="breadcrumb-item active">Edit Post</li>
            </ol>
        </nav>
        <h1>Edit Post</h1>
        {renderForm post}
    |]

is from the code for the Blog project in the Creating Your First Project section of the IHP guide.

I've mostly converted it from HSX to blaze-html here:

instance View EditView where
    html EditView { .. } = do
        H.nav $ do
            H.ol ! A.class_ "breadcrumb" $ do
                H.li ! A.class_ "breadcrumb-item" $ do
                    H.a ! A.href "PostsAction" $ do
                        "Posts"
                H.li ! A.class_ "breadcrumb-item active" $ do
                    "Edit Post"
        H.h1 "Edit Post"
        renderForm post

The last bit I'm wondering about is this one:

<a href={PostsAction}>Posts</a>

If I do the following:

H.a ! A.href PostsAction $ do
    "Posts"

I get this message:

• Couldn't match expected type ‘H.AttributeValue’
              with actual type ‘PostsController’
• In the first argument of ‘A.href’, namely ‘PostsAction’
  In the second argument of ‘(!)’, namely ‘A.href PostsAction’
  In the expression: H.a ! A.href PostsActiontypecheck
PostsAction
Defined at /home/dharmatech/Dropbox/Documents/ihp-blog/blog/Web/Types.hs:13:7

What's a good way to pass PostsAction to A.href?

(If there are other ways to make the blaze-html expression more idiomatic, feel free to recommend as well. :-))

Update 1

When I use the following, along the lines of what Willem suggested in his answer below:

instance View EditView where
    html EditView { .. } = do
        H.nav $ do
            H.ol ! A.class_ "breadcrumb" $ do
                H.li ! A.class_ "breadcrumb-item" $ do
                    H.a ! A.href (fromString (show PostsAction)) $ do
                        "Posts"
                H.li ! A.class_ "breadcrumb-item active" $ do
                    "Edit Post"
        H.h1 "Edit Post"
        renderForm post

I get the following:

• Couldn't match type ‘Text’ with ‘[Char]’
  Expected type: String
    Actual type: Text
• In the first argument of ‘fromString’, namely
    ‘(show PostsAction)’
  In the first argument of ‘A.href’, namely
    ‘(fromString (show PostsAction))’
  In the second argument of ‘(!)’, namely
    ‘A.href (fromString (show PostsAction))’typecheck

Perhaps I need to import a Text version of fromString?

Update 2

I've added the following import:

import Data.String(IsString(fromString))

However, the error message is the same:

• Couldn't match type ‘Text’ with ‘[Char]’
  Expected type: String
    Actual type: Text
• In the first argument of ‘fromString’, namely
    ‘(show PostsAction)’
  In the first argument of ‘A.href’, namely
    ‘(fromString (show PostsAction))’
  In the second argument of ‘(!)’, namely
    ‘A.href (fromString (show PostsAction))’typecheck

Update 3

If I hover over show the following signature is shown:

show :: forall a. Show a => a -> Text

And for fromString:

fromString :: forall a. IsString a => String -> a

So I believe that's where the mismatch is.

Update 4

This being a typical IHP view file, I have the following at the top for imports:

module Web.View.Posts.Edit where
import Web.View.Prelude

import qualified Text.Blaze.Html5 as H
import qualified Text.Blaze.Html5.Attributes as A

Solution

  • As the documentation on Inline Haskell says:

    If the variable is another HSX expression, a blaze HTML element, a text or string: it is just included as you would expect.

    If the variable is any other custom Haskell data structure: it will first be converted to a string representation by calling show on it. You can add a custom ToHtml (import it from IHP.HSX.ToHtml) instance, to customize rendering a data structure.

    So unless there was a ToHTML in the [hsx|…] quasiquoter for {PostAction}, you thus should apply show, next we call fromString :: IsString a => String -> a to it to convert it to an AttributeValue.

    The code is thus equivalent to:

    instance View EditView where
        html EditView { .. } = do
            H.nav $ do
                H.ol ! A.class_ "breadcrumb" $ do
                    H.li ! A.class_ "breadcrumb-item" $ do
                        H.a ! A.href (fromString (show PostsAction)) $ do
                            "Posts"
                    H.li ! A.class_ "breadcrumb-item active" $ do
                        "Edit Post"
            H.h1 "Edit Post"
            renderForm post