How do I change the in an IHP app?</a></h1> </div> <div class="grid fw-wrap pb8 mb16 bb bc-black-075"> <div class="grid--cell ws-nowrap mr16 mb8" title="2016-01-12 19:07:53Z"> <span class="fc-light mr2">Asked</span> <time itemprop="dateCreated" datetime="2020-10-10T15:30:29.223" class="fromnow">Oct 10 '20 at 15:30</time> </div> <div class="grid--cell ws-nowrap mr16 mb8"> <span class="fc-light mr2">Active</span> <time class="fromnow" title="2021-09-12T18:37:16.523" datetime="2021-09-12T18:37:16.523">Sep 12 '21 at 18:37</a> </div> <div class="grid--cell ws-nowrap mb8" title="Viewed 129 times"> <span class="fc-light mr2">Viewed</span> 129 times </div> </div> <div id="mainbar" role="main" aria-label="questions and answers"> <div id="question" class="question" data-questionid="64295142" data-ownerid="69663" data-score="3"> <div class="post-layout"> <div class="votecell post-layout--left"> <div class="js-voting-container grid jc-center fd-column ai-stretch gs4 fc-black-200" data-post-id="64295142"> <button class="js-vote-up-btn grid--cell s-btn s-btn__unset c-pointer"><svg aria-hidden="true" class="m0 svg-icon iconArrowUpLg" width="36" height="36" viewBox="0 0 36 36"><path d="M2 26h32L18 10 2 26z"></path></svg></button> <div class="js-vote-count grid--cell fc-black-500 fs-title grid fd-column ai-center" itemprop="upvoteCount" data-value="3">3</div> <button class="js-bookmark-btn s-btn s-btn__unset c-pointer py4"> <svg aria-hidden="true" class="svg-icon iconBookmark" width="18" height="18" viewBox="0 0 18 18"><path d="M6 1a2 2 0 00-2 2v14l5-4 5 4V3a2 2 0 00-2-2H6zm3.9 3.83h2.9l-2.35 1.7.9 2.77L9 7.59l-2.35 1.7.9-2.76-2.35-1.7h2.9L9 2.06l.9 2.77z"></path></svg> <div class="js-bookmark-count mt4" data-value=""></div> </button> </div> </div> <div class="postcell post-layout--right"> <div class="s-prose js-post-body" itemprop="text"><p>I see <code><title>App</title></code> is hardcoded in <code>defaultLayout</code> in Web/View/Layout.hs, and Web/View/Context.hs has</p> <pre><code> let viewContext = ViewContext { requestContext = ?requestContext, user = currentUserOrNothing, flashMessages, controllerContext = ?controllerContext, layout = let ?viewContext = viewContext in defaultLayout } </code></pre> <p>but how do I use a different function for a specific View? The <code>html</code> function of the View class doesn't seem to return a new context, just a new html for part of the page.</p></div> <div class="mt24 mb12"> <div class="post-taglist grid gs4 gsy fd-column"> <div class="grid ps-relative"> <a href="../../questions/tagged/haskell" class="post-tag js-gps-track" title="show questions tagged 'haskell'" rel="tag">haskell</a> <a href="../../questions/tagged/ihp" class="post-tag js-gps-track" title="show questions tagged 'ihp'" rel="tag">ihp</a> </div> </div> </div> <div class="mb0"> <div class="mt16 grid gs8 gsy fw-wrap jc-end ai-start pt4 mb16"> <div class="grid--cell mr16 fl1 w96"></div> <div class="post-signature owner grid--cell"> <div class="s-user-card s-user-card"> <time class="s-user-card--time" datetime="asked Oct 10 '20 at 15:30">asked Oct 10 '20 at 15:30</time> <a href="../../users/69663/unhammer" class="s-avatar s-avatar__32 s-user-card--avatar"> <img class="s-avatar--image" src="../../users/profiles/69663.webp" data-jdenticon-width="32" data-jdenticon-height="32" data-jdenticon-value="unhammer" /> </a> <div class="s-user-card--info"> <a href="../../users/69663/unhammer" class="s-user-card--link">unhammer</a> <ul class="s-user-card--awards"> <li class="s-user-card--rep" title="reputation score">4,306</li> <li class="s-award-bling s-award-bling__gold" title="2 gold badges">2</li> <li class="s-award-bling s-award-bling__silver" title="39 silver badges">39</li> <li class="s-award-bling s-award-bling__bronze" title="52 bronze badges">52</li> </ul> </div> </div> </div> </div> </div> </div> <div class="post-layout--right js-post-comments-component"> </div> </div> </div> <div id="answers"> <a name="tab-top"></a> <div id="answers-header"> <div class="answers-subheader grid ai-center mb8"> <div class="grid--cell fl1"> <h2 class="mb0" data-answercount="9">2 Answers<span style="display:none;" itemprop="answerCount">2</span></h2> </div> </div> </div> <a name="64295143"></a> <div id="answer-64295143" class="answer " data-answerid="64295143" data-ownerid="69663" data-score="3" itemprop="suggestedAnswer" itemscope="" itemtype="https://schema.org/Answer"> <div class="post-layout"> <div class="votecell post-layout--left"> <div class="js-voting-container grid jc-center fd-column ai-stretch gs4 fc-black-200" data-post-id="64295143"> <button class="js-vote-up-btn grid--cell s-btn s-btn__unset c-pointer"><svg aria-hidden="true" class="m0 svg-icon iconArrowUpLg" width="36" height="36" viewBox="0 0 36 36"><path d="M2 26h32L18 10 2 26z"></path></svg></button> <div class="js-vote-count grid--cell fc-black-500 fs-title grid fd-column ai-center" itemprop="upvoteCount" data-value="3">3</div> </div> </div> <div class="postcell post-layout--right"> <div class="s-prose js-post-body" itemprop="text"><p>Figured it out: There's a <code>beforeRender</code> function you can override in the <code>View</code> class where you can set it, e.g.</p> <pre><code>data ShowView = ShowView { targets :: [Include "comments" Post], postTitle :: Text } instance View ShowView ViewContext where beforeRender (context, view) = (context { layout = myLayout (postTitle view) }, view) html ShowView { .. } = [hsx| … |] </code></pre> <p>(and set <code>postTitle</code> in Web/Controller/Posts.hs), then change Web/View/Layout.hs to do</p> <pre><code>defaultLayout :: Html -> Html defaultLayout = myLayout "App" myLayout :: Text -> Html -> Html myLayout title inner = H.docTypeHtml ! A.lang "en" $ [hsx| <head> {metaTags} {stylesheets} {scripts} <title>{title}</title> </head> <body> <div class="container mt-4"> {renderFlashMessages} {inner} </div> </body> |] </code></pre></div> <div class="mb0"> <div class="mt16 grid gs8 gsy fw-wrap jc-end ai-start pt4 mb16"> <div class="grid--cell mr16 fl1 w96"></div> <div class="post-signature owner grid--cell"> <div class="s-user-card s-user-card"> <time class="s-user-card--time" datetime="answered Oct 10 '20 at 15:30">answered Oct 10 '20 at 15:30</time> <a href="../../users/69663/unhammer" class="s-avatar s-avatar__32 s-user-card--avatar"> <img class="s-avatar--image" src="../../users/profiles/69663.webp" data-jdenticon-width="32" data-jdenticon-height="32" data-jdenticon-value="unhammer" /> </a> <div class="s-user-card--info"> <a href="../../users/69663/unhammer" class="s-user-card--link">unhammer</a> <ul class="s-user-card--awards"> <li class="s-user-card--rep" title="reputation score">4,306</li> <li class="s-award-bling s-award-bling__gold" title="2 gold badges">2</li> <li class="s-award-bling s-award-bling__silver" title="39 silver badges">39</li> <li class="s-award-bling s-award-bling__bronze" title="52 bronze badges">52</li> </ul> </div> </div> </div> </div> </div> </div> <div class="post-layout--right js-post-comments-component"> </div> </div> </div> <a name="69154228"></a> <div id="answer-69154228" class="answer accepted-answer" data-answerid="69154228" data-ownerid="1068664" data-score="2" itemprop="acceptedAnswer" itemscope="" itemtype="https://schema.org/Answer"> <div class="post-layout"> <div class="votecell post-layout--left"> <div class="js-voting-container grid jc-center fd-column ai-stretch gs4 fc-black-200" data-post-id="69154228"> <button class="js-vote-up-btn grid--cell s-btn s-btn__unset c-pointer"><svg aria-hidden="true" class="m0 svg-icon iconArrowUpLg" width="36" height="36" viewBox="0 0 36 36"><path d="M2 26h32L18 10 2 26z"></path></svg></button> <div class="js-vote-count grid--cell fc-black-500 fs-title grid fd-column ai-center" itemprop="upvoteCount" data-value="2">2</div> <div class="js-accepted-answer-indicator grid--cell fc-green-500 py6 mtn8"><div class="ta-center"><svg aria-hidden="true" class="svg-icon iconCheckmarkLg" width="36" height="36" viewBox="0 0 36 36"><path d="m6 14 8 8L30 6v8L14 30l-8-8v-8z"></path></svg></div></div> </div> </div> <div class="postcell post-layout--right"> <div class="s-prose js-post-body" itemprop="text"><p>There is now a <code>pageTitle</code> function you could use in view (e.g. your layout) like this:</p> <pre class="lang-hs prettyprint-override"><code>[hsx| <head> <title>{pageTitle}</title> </head> |] </code></pre> <p><a class="external-link" href="https://github.com/digitallyinduced/ihp/blob/18f104da69c526ff9e8ad3a6cdaedc6d39afb38c/IHP/PageTitle/ViewFunctions.hs#L54" rel="nofollow noreferrer">https://github.com/digitallyinduced/ihp/blob/18f104da69c526ff9e8ad3a6cdaedc6d39afb38c/IHP/PageTitle/ViewFunctions.hs#L54</a></p> <p>Which can in turn be set in action using <code>setTitle</code></p> <pre class="lang-hs prettyprint-override"><code>action ShowProjectAction { projectId } = do project <- fetch projectId setTitle (get #title project) </code></pre> <p><a class="external-link" href="https://github.com/digitallyinduced/ihp/blob/d98c3d6eb8145d859c9ce461e7d1367be5be7337/IHP/PageTitle/ControllerFunctions.hs#L32" rel="nofollow noreferrer">https://github.com/digitallyinduced/ihp/blob/d98c3d6eb8145d859c9ce461e7d1367be5be7337/IHP/PageTitle/ControllerFunctions.hs#L32</a></p> <p>Latest IHP also generates the following layout s.t. you get it automatically with a fallback:</p> <pre class="lang-hs prettyprint-override"><code>defaultLayout :: Html -> Html defaultLayout inner = H.docTypeHtml ! A.lang "en" $ [hsx| <head> {metaTags} {stylesheets} {scripts} <title>{pageTitleOrDefault "App"}</title> </head> <body> <div class="container mt-4"> {renderFlashMessages} {inner} </div> </body> |] </code></pre></div> <div class="mb0"> <div class="mt16 grid gs8 gsy fw-wrap jc-end ai-start pt4 mb16"> <div class="grid--cell mr16 fl1 w96"></div> <div class="post-signature grid--cell"> <div class="s-user-card s-user-card"> <time class="s-user-card--time" datetime="answered Sep 12 '21 at 18:37">answered Sep 12 '21 at 18:37</time> <a href="../../users/1068664/limouren" class="s-avatar s-avatar__32 s-user-card--avatar"> <img class="s-avatar--image" src="../../users/profiles/1068664.webp" data-jdenticon-width="32" data-jdenticon-height="32" data-jdenticon-value="limouren" /> </a> <div class="s-user-card--info"> <a href="../../users/1068664/limouren" class="s-user-card--link">limouren</a> <ul class="s-user-card--awards"> <li class="s-user-card--rep" title="reputation score">116</li> <li class="s-award-bling s-award-bling__bronze" title="4 bronze badges">4</li> </ul> </div> </div> </div> </div> </div> </div> <div class="post-layout--right js-post-comments-component"> </div> </div> </div> </div> </div> </div> </div> <script src="../../static/js/stack-icons.js"></script> <script src="../../static/js/fromnow.js"></script> </body> </html>