[web-devel] [Yesod] widgets in default layout
michael at snoyman.com
Sun Feb 13 16:44:33 CET 2011
On Sun, Feb 13, 2011 at 5:28 PM, Dmitry Kurochkin
<dmitry.kurochkin at gmail.com> wrote:
> Still the argument remains. I want to have all menu-related code in a
> separate module.
OK. As I said, this is possible, and it sounds like you already got
90% of the way there. I don't know what's holding you up until I see
your code. My initial reaction is still that this is a bad idea in
general, though I *am* reconsidering that position. It might make
sense to alter the approach used by the scaffolded site.
>> >> > 2. Widget does not work in default layout.
>> >> >
>> >> > I guess this is a known and expected behavior. My feeling is that
>> >> > hamletToRepHtml can not embed widgets because it may be too late to add
>> >> > cassius and julius. As a workaround I split default layout into outer
>> >> > and inner layout. Outer layout renders just HTML <head> and <body>.
>> >> > While outer layout is rendered as a widget that embeds the actual page
>> >> > contents. Since outer layout is rendered as a widget, it may embed other
>> >> > widgets like menu.
>> >> >
>> >> > I imagine that hamletToRepHtml could render all embedded widgets before
>> >> > the main body. Though, it may be difficult to implement, have
>> >> > performance or other issues. Anyway, I think it is not uncommon to
>> >> > include a widget in default layout. So Yesod should provide an easy way
>> >> > to do it.
>> >> You should try looking at the scaffolded site: the function you want
>> >> to use is widgetToPageContent. It converts a complete Widget into
>> >> the individual pieces that you need.
>> > Yes, widgetToPageContent is used to convert the widget from handler and
>> > produces a set of pieces for page generation (pc). If I use it for a
>> > menu widget, I will get another PageContent (pc1). Now I need to take
>> > body from pc1, and merge other pieces of pc1 with pc. E.g. menu widget
>> > PageContent. I did not find an existing function to do this. Did I miss
>> > it?
>> Just combine the two widgets and call widgetToPageContent once:
>> defaultLayout widget = do
>> pc <- widgetToPageContents $ do
>> hamletToRepHtml ...
>> You can see an example of this in the Yesod docs site.
> I thought this would result in menuWidget placed directly before the
> main widget body, right? In many cases simple concatenation is not
Then just modify menuWidget to take a Widget as an argument:
menuWidget :: GWidget s m () -> GWidget s m ()
menuWidget w = do
This is the very reason why we have polymorphic hamlet, so you can even do:
menuWidget w = [$hamlet|
In fact, if you put that into a separate menu-widget.hamlet file, you
might get the results you were looking for originally all the
>> Just to confirm: are you talking for general widgets, or just widgets
>> to be called from defaultLayout? As I mention above, the former can
>> easily be put in separate modules, the latter would require more work.
> I am talking about defaultLayout widgets. In general, reasons for
> putting widgets into separate modules does not depend on whether they
> are used in defaultLayout. Though, I agree that the fact that only
> defaultLayout widgets must be put into the Yesod instance module
> somewhat improves the situation.
> IMO from user point of view it does not matter much if widget is used in
> handler or in defaultLayout. In most cases, at least. I just create a
> menu widget and want be able to use it anywhere (even both in handlers
> and defaultLayout). E.g. in my case the only difference between handler
> and defaulLayout widget is the type signature, implementation does not
Nonetheless, these *are* the rules that exist in Haskell. To a certain
extent, separating out mkYesodDispatch into Controller.hs is a similar
hack to this. In that case, I think that the added benefit of separate
handler modules definitely justifies using this technique. I'm simply
not (yet) convinced that the benefit here is big enough to warrant a
More information about the web-devel