Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature Request: Test for block content #1911

Open
fusepilot opened this issue Mar 29, 2015 · 11 comments
Open

Feature Request: Test for block content #1911

fusepilot opened this issue Mar 29, 2015 · 11 comments

Comments

@fusepilot
Copy link

I would like to be able to have defined blocks show only if they have content provided to them. Something like:

if block features
    section.features
        h2 Features
        .content
            block features

if block related
    section.related
        h2 Related Products
        .content
            block related

I'm currently working around this by using jade-lexer and jade-parser to find all defined NamedBlocks and provide them as locals in a object called blocks. I can use this like:

if blocks.features
    section.features
        h2 Features
        .content
            block features

if blocks.related
    section.related
        h2 Related Products
        .content
            block related

Not really ideal. It seems like you should be able to check if the blocks have been defined out of box.

@TimothyGu
Copy link
Member

It would be difficult to implement this in practice, since if is always translated to an if () {} in runtime JS code, but blocks for extend are interpreted at compile time.

This differs from mixins, which are literally wrapped JavaScript functions. When you +mixinName('adsf'), you are actually calling a function at render time, so you can check if block (→if (block)) at render time.

@fusepilot
Copy link
Author

Sure, I didn't mean to imply that the final syntax should be exactly as I wrote above. Whatever is appropriate to achieve the resulting functionallity.

And are you suggesting there's a clean way to do this with mixins? If so, I'm not seeing how without parsing the AST at runtime. Which seems a bit much to achieve this simple 'check'.

@TimothyGu
Copy link
Member

And are you suggesting there's a clean way to do this with mixins?

No. mixins are simply not suited for this purpose.

I also toyed with the idea of wrapping the extend block with a mixin (like this:

mixin related
  if block
    section.related
      h2 Related Products
      .content
        block

html
  body
    +related
      block related

but that didn't work out since block is always defined in the mixin and no return code is emitted.

If so, I'm not seeing how without parsing the AST at runtime. Which seems a bit much to achieve this simple 'check'.

I agree.

@TimothyGu
Copy link
Member

Just for fun, I did finally get something extremely ugly and hacky working (DO NOT USE THIS):

//- layout.jade
doctype html

mixin optional(cl, desc)
  //- replace proper buffer with a dummy one to test if block is empty or not
  - var oldBuf = buf
  - buf = []
  block
  - var blockContent = buf.join('').trim()
  - buf = oldBuf
  if blockContent
    section(class=cl)
      h2= desc
      .content
        block

html
  body
    +optional('features', 'Features')
      block features
    +optional('related', 'Related Products')
      block related
//- extend.jade

extends layout.jade

block features
  ul
    li Supports Jade templating engine.
    li Blazing-fast.
<!DOCTYPE html>
<html>
  <body>
    <section class="features">
      <h2>Features</h2>
      <div class="content">
        <ul>
          <li>Supports Jade templating engine.</li>
          <li>Blazing-fast.</li>
        </ul>
      </div>
    </section>
  </body>
</html>

But it's subpar and uses knowledge of Jade internals, so do NOT use this.

@TimothyGu
Copy link
Member

So, Jade is extremely opinionated, which contributes to its prettiness in templates that fit its standards and extreme ugliness otherwise.

In real world, you might want to just put the headings and .content into the block itself. It will save you a lot of hassle.

@fusepilot
Copy link
Author

Interesting. Thank you for the insight.

Will 2.0 implement anything that would perhaps make this more conise/easier?

Also, just to ensure clairity, I'm only looking for an functional equivalent to Rail's content_for?.

http://api.rubyonrails.org/classes/ActionView/Helpers/CaptureHelper.html#method-i-content_for-3F
http://stackoverflow.com/questions/193838/rails-check-if-yield-area-is-defined-in-content-for

@ForbesLindesay
Copy link
Member

We could do something like this without too much difficulty. This is the reverse problem of dynamic include. i.e. it is impossible to use a value that is only known at runtime and then use it to change behaviour at compile time. It is possible to take a value that is only known at compile time, and make that available at runtime though.

We could, for example, take a regexp like /\bblock ([a-zA-Z_0-9]+)\b/ which would never match any valid JavaScript code, and replace all occurrences of that with either true or false depending on the child templates. This could be done at compile time. This would certainly be a fun/interesting academic exercise.

What I'm less sure of is whether this is a good idea. We do support multiple inheritance, which seems like it should cover this use case quite nicely. i.e. instead of:

doctype html
html
  if block features
    section.features
      h2 Features
      .content
        block features

  if block related
    section.related
      h2 Related Products
      .content
        block related

just do:

doctype html
html
  block content
extends ./layout.jade
block content
  section.features
    h2 Features
    .content
      block features
extends ./layout.jade
block content
  section.related
    h2 Related Products
    .content
      block related

Then just extend either layout-features.jade or layout-related.jade as appropriate.

@fridays
Copy link

fridays commented Nov 11, 2015

Hey guys. I am new to Jade but this mixin/block combination worked out for me when trying to wrap a block only if it has contents:

// mixins.jade
mixin content
    if block
        .content-wrapper
            block

// layout.jade
doctype
html
    block content

// example.jade
extends layout
block content
    +content
        p This will be wrapped.

@TimothyGu
Copy link
Member

@fridays, no, we are talking about detecting inheritance blocks here (i.e. if block content in your example, in layout.jade).

@meodai
Copy link

meodai commented Feb 27, 2017

any news on this? This would be so helpful. Would avoid a lot of file overhead

@olivmonnier
Copy link

As temporary solution, maybe should use mixin like that :

mixin layout(isHeader, isContent, isFooter)
  if isHeader
    block header
  if isContent
    block content
  if isFooter
    block footer
+layout(true, true, false)
  block header
    h1 Hello
  block content
    p hi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants