pugjs / pug

Pug – robust, elegant, feature rich template engine for Node.js
https://pugjs.org
21.67k stars 1.95k forks source link

Inheriting view tied to layout #366

Closed dizlexik closed 12 years ago

dizlexik commented 13 years ago

I was super-pumped when I first read about the new template inheritance in Jade but when I looked a little closer I realized that I'm not in love with the implementation :( So basically the inheriting views are tied to their parent layout, right? What I really want to do is have multiple layouts (for example, one for web, one for mobile) that can expose the same blocks. I don't think it should be my view's responsibility to specify (via extends) which layout they will be rendered within. That should be the controller's job. I would love this implementation of blocks exactly the way it is if the whole concept of extends (and forcing me to set { layout: false }) were thrown out. Is it possible to make this more dynamic like that? I guess this wouldn't exactly be "inheritance" if you did it this way... but it would be awesome and would totally solve the biggest issue I've had with Jade since the beginning. I just want to be able to do simple things like include an extra CSS or JS file from within my views and have them appear in the correct spots in my layout (whichever one happens to be specified by the controller). Now that I think about it this is really not what template inheritance was created to solve, but the concept of blocks would be so perfect for this. Really sorry about the stream-of-consciousness post here... hopefully I got my point across.

tj commented 13 years ago

well that's essentially what jade had previously via express, it's the same issue just backwards haha. This is more like django's template inheritance, where the "page template" or initial template is nothing special, there's no special notion of a layout, it just simply extends something else. For example you could also have a admin.jade template extend user.jade etc

tj commented 13 years ago

that being said I think an api could be exposed to do what you want, but it would be kinda ugly, you would have to specify a filename for what extends what, since that notion of a page/layout template is not there

dizlexik commented 13 years ago

What about this (I'm thinking in terms of Express again, but it should work on its own too I think):

layout.jade:

html
  head
    title Test
    link(rel='stylesheet', href='/css/style.css')
    block render styles
  body
    != body
    script(src='/js/script.js')
    block render scripts

page.jade:

block styles
  link(rel='stylesheet', href='/css/extra.css')

block scripts
  script(src='/js/extra.js')

p Sample content.

Something to that effect would be awesome! Especially in conjunction with block append from #355 for multiple levels of layouts.

JustinBeckwith commented 12 years ago

I just ran into this same issue. I'm trying to use the same child views for different parent layouts, and right now I just can't do that. It would be nice if the child view wasn't bound to the parent view.

tj commented 12 years ago

there are benefits to either implementation, perhaps the extends call could be a jade option as well, though it's a compile-time thing so it might be a little complicated. at worst you could use extends / includes to have a few views that simply include your normal one extending others

dizlexik commented 12 years ago

I've currently implemented a hack for this that I don't hate too much so I thought I'd share it here. I ended up using @bminer's buf hack from #374 to pass chunks of Jade-generated HTML from views to layouts. In my Express config I have app.locals({ blocks: {} }) and I do the following in views:

styles = buf.length
  link(ref='stylesheet', href='extra.css')
  - blocks.styles = buf.splice(styles, buf.length).join('')
scripts = buf.length
  script(src='extra.css')
  - blocks.scripts = buf.splice(scripts, buf.length).join('')

Then I have blocks.styles and blocks.scripts to use in my layout. Hurray! I'd still love to see this functionality implemented natively in Jade somehow but for now this works fine.

pierreis commented 12 years ago

I would also love to see this feature added to Jade. As of today, I did not find any decent way to do this. By the way, do anybody have some workaround to share for this issue?

By the way, I would prefer some syntax like extend #{somevariable}, which would be even more flexible, by allowing to define dynamic extends at any point of the hierarchy of templates, and not only for the last one.

tj commented 12 years ago

This issue has been inactive for over 2 months so I'm closing it. If you think it's still an issue re-open. - tjbot